Sending mail with an ESP8266

Sending mail with an ESP8266 can be handy for a variety of things. I use it to occasionally have a remote ESP8266 send me a message it is still ok and functioning.
It is possible to have the ESP8266 directly access your mail server (such as Gmail, Hotmail, Outlook) and send a message through that, but many mailservers will refuse mail that is being sent from a different domain (your ip) than the mailserver’s.
In those cases is therefore safer to use a third party service like As long as you stay below a certain limit of emails, one can get a free account.
I will show how to work with both.

Using SMTP2go

After signing up  for smtp2go, you will need to choose a user id and password for your smtp log in. You thus have two sets of id and password: one for your user account and one for the mails you send.
The latter, you need to encode in base 64 to use  from your ESP8266. You can do that with an online encoder.
As there is no need to re-invent the wheel, I used this program as a basis and reworked that to my needs, but as your needs might be different from mine, I will just give a general example.
In order to send something more useful than ‘Hello World’, we are going to send the supply voltage and the chip ID. In real life I do not send the suply voltage as that is not so useful, but I send the battery voltage. But to keep it simple in this example we will stick to the supply voltage, which we get with ESP.getVcc().
The program is like this: (NOTE: the code might be badly formatted by wordpress, make sure you copy it completely)

#include <ESP8266WiFi.h>  // the ESP8266WiFi.h  lib
const char* SSID = "YourSSID";
const char* PASS = "YourPW";
char server[] = "";

WiFiClient client;
void setup()
  Serial.print("Connecting To ");
  WiFi.begin(SSID, PASS);
  while (WiFi.status() != WL_CONNECTED)
  Serial.println("WiFi Connected");
  Serial.print("IP address: ");
  byte ret = sendEmail();

void loop()

byte sendEmail()
  byte thisByte = 0;
  byte respCode;

  if (client.connect(server, 2525) == 1) {
  } else {
    Serial.println(F("connection failed"));
    return 0;
  if (!eRcv()) return 0;

  Serial.println(F("Sending EHLO"));
  if (!eRcv()) return 0;
  Serial.println(F("Sending auth login"));
  client.println("auth login");
  if (!eRcv()) return 0;
  Serial.println(F("Sending User"));
  // Change to your base64, ASCII encoded user
  client.println("ZV83MTAwMEBnbWFljC5jb31="); // SMTP UserID
  if (!eRcv()) return 0;
  Serial.println(F("Sending Password"));
  // change to your base64, ASCII encoded password
  client.println("X5pqVU9vYlJjY7Bq");//  SMTP Passw
     if (!eRcv()) return 0;
    Serial.println(F("Sending From"));   // change to your email address (sender)
   client.println(F("MAIL From:"));// not important 
   if (!eRcv()) return 0;   // change to recipient address
    Serial.println(F("Sending To"));
    client.println(F("RCPT To:"));
    if (!eRcv()) return 0;
    Serial.println(F("Sending DATA"));
    if (!eRcv()) return 0;
    Serial.println(F("Sending email"));   // change to recipient address
   client.println(F("To:"));   // change to your address
 client.println(F("Subject: Emails from ESp8266\r\n"));
    client.print(F("Power is: "));
    client.print(F("Device Chip ID: "));
    Serial.print(F("Voltage is: "));
    if (!eRcv()) return 0;
    Serial.println(F("Sending QUIT"));
    if (!eRcv()) return 0;
    return 1;
  byte eRcv()
    byte respCode;
    byte thisByte;
    int loopCount = 0;
    while (!client.available())
      loopCount++;     // if nothing received for 10 seconds, timeout
      if (loopCount > 10000) {
      return 0;

  respCode = client.peek();
  while (client.available())
    thisByte =;

  if (respCode >= '4')
    //  efail();
    return 0;
  return 1;

In the example I use “gmail” but ofcourse this can be any other mailservice>
In the program you will also see a line with “"));// not important“. I may be wrong but it is not that important what that says. It is the identity under which your mails are grouped in the smpt2go dashboard. Maybe it is easiest to make that equal to the sender address, but it isnot important for the functioning of the program.

The strings that are send are rather flexible. Instead of
client.println(F("Subject: Emails from ESp8266\r\n"));
On can also do:
client.print(F("Subject: "));
if (condition == met)

Using Google, Hotmail, Outlook, Yahoo mailservers directly

If you prefer to not use an intermediate mail server, it is possible to use a mailserver such as your gmail or Hotmail or any other. That is easiest done with the ESP_Mail_Client library. The HTML Example is a good basis to start with.
For Gmail use the following settings:

  • SMTP Server:
  • SMTP username: Complete Gmail address
  • SMTP password: Your Gmail password
  • SMTP port (TLS): 587
  • SMTP port (SSL): 465
  • SMTP TLS/SSL required: yes

For Hotmail the settings are:

  • SMTP Server:
  • SMTP Username: Complete Live/Hotmail email address
  • SMTP Password: Your Windows Live Hotmail password
  • SMTP Port: 587
  • SMTP TLS/SSL Required: Yes

for Outlook:

  • SMTP Server:
  • SMTP Username: Complete Outlook email address
  • SMTP Password: Your Outlook password
  • SMTP Port: 587
  • SMTP TLS/SSL Required: Yes

for Yahoo:

SMTP server:
SMTP username: Your full  Yahoo email address (including
SMTP password: Your  Yahoo Mail password
SMTP port: 465 or  587
SMTP TLS/SSL Required: Yes

 * This example will send the Email in
 * the html version.
 * Created by K. Suwatchai (Mobizt)
 * Email:
 * Github:
 * Copyright (c) 2021 mobizt

//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled.

#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESP_Mail_Client.h>

#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"

/** The smtp host name e.g. for GMail or for Outlook or
 * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
 * and use the app password as password with your yahoo mail account to login.
 * The google app password signin is also available
#define SMTP_HOST "################"

/** The smtp port e.g. 
 * 25  or esp_mail_smtp_port_25
 * 465 or esp_mail_smtp_port_465
 * 587 or esp_mail_smtp_port_587
#define SMTP_PORT 25

/* The log in credentials */
#define AUTHOR_EMAIL "################"
#define AUTHOR_PASSWORD "################"

/* The SMTP Session object used for Email sending */
SMTPSession smtp;

/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status);

void setup()


#if defined(ARDUINO_ARCH_SAMD)
  while (!Serial)
  Serial.println("**** Custom built WiFiNINA firmware need to be installed.****\nTo install firmware, read the instruction here,");



  Serial.print("Connecting to AP");

  while (WiFi.status() != WL_CONNECTED)

  Serial.println("WiFi connected.");
  Serial.println("IP address: ");

  /** Enable the debug via Serial port
   * none debug or 0
   * basic debug or 1

  /* Set the callback function to get the sending results */

  /* Declare the session config data */
  ESP_Mail_Session session;

  /** ########################################################
   * Some properties of SMTPSession data and parameters pass to 
   * SMTP_Message class accept the pointer to constant char
   * i.e. const char*. 
   * You may assign a string literal to that properties or function 
   * like below example.
   * session.login.user_domain = "";
   * session.login.user_domain = String("").c_str();
   * or
   * String doman = "";
   * session.login.user_domain = domain.c_str();
   * And
   * String name = "Jack " + String("dawson");
   * String email = "jack_dawson" + String(123) + "";
   * message.addRecipient(name.c_str(), email.c_str());
   * message.addHeader(String("Message-ID: <>").c_str());
   * or
   * String header = "Message-ID: <>";
   * message.addHeader(header.c_str());
   * ###########################################################

  /* Set the session config */
  session.server.host_name = SMTP_HOST;
  session.server.port = SMTP_PORT; = AUTHOR_EMAIL;
  session.login.password = AUTHOR_PASSWORD;
  session.login.user_domain = "";

  /* Declare the message class */
  SMTP_Message message;

  /* Set the message headers */ = "ESP Mail"; = AUTHOR_EMAIL;
  message.subject = "Test sending html Email";
  message.addRecipient("Admin", "####@#####_dot_com");

  String htmlMsg = "<p>This is the <span style=\"color:#ff0000;\">html text</span> message.</p><p>The message was sent via ESP device.</p>";
  message.html.content = htmlMsg.c_str();

  /** The html text message character set e.g.
   * us-ascii
   * utf-8
   * utf-7
   * The default value is utf-8
  message.html.charSet = "us-ascii";

  /** The content transfer encoding e.g.
   * enc_7bit or "7bit" (not encoded)
   * enc_qp or "quoted-printable" (encoded)
   * enc_base64 or "base64" (encoded)
   * enc_binary or "binary" (not encoded)
   * enc_8bit or "8bit" (not encoded)
   * The default value is "7bit"
  message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit;

  /** The message priority
   * esp_mail_smtp_priority_high or 1
   * esp_mail_smtp_priority_normal or 3
   * esp_mail_smtp_priority_low or 5
   * The default value is esp_mail_smtp_priority_low
  message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low;

  /** The Delivery Status Notifications e.g.
   * esp_mail_smtp_notify_never
   * esp_mail_smtp_notify_success
   * esp_mail_smtp_notify_failure
   * esp_mail_smtp_notify_delay
   * The default value is esp_mail_smtp_notify_never
  message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay;

  /* Set the custom message header */
  message.addHeader("Message-ID: <>");

  /* Connect to server with the session config */
  if (!smtp.connect(&session))

  /* Start sending Email and close the session */
  if (!MailClient.sendMail(&smtp, &message))
    Serial.println("Error sending Email, " + smtp.errorReason());

  ESP_MAIL_PRINTF("Free Heap: %d\n", MailClient.getFreeHeap());

void loop()

/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status)
  /* Print the current status */

  /* Print the sending result */
  if (status.success())
    ESP_MAIL_PRINTF("Message sent success: %d\n", status.completedCount());
    ESP_MAIL_PRINTF("Message sent failled: %d\n", status.failedCount());
    struct tm dt;

    for (size_t i = 0; i < smtp.sendingResult.size(); i++)
      /* Get the result item */
      SMTP_Result result = smtp.sendingResult.getItem(i);
      time_t ts = (time_t)result.timestamp;
      localtime_r(&ts, &dt);

      ESP_MAIL_PRINTF("Message No: %d\n", i + 1);
      ESP_MAIL_PRINTF("Status: %s\n", result.completed ? "success" : "failed");
      ESP_MAIL_PRINTF("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec);
      ESP_MAIL_PRINTF("Recipient: %s\n", result.recipients);
      ESP_MAIL_PRINTF("Subject: %s\n", result.subject);

43 thoughts on “Sending mail with an ESP8266”

  1. Nice! A few remarks:
    You can also use gmail as your outbound relay server. However, you better not do this if you don’t have two step authentication enabled (which you should!). You can (and must) then create a separate password for services like smtp. It actually works very good.

    The mailto field is not important for sending the mail but some filters do use it. For example, the relay from allows you to only use the domain of you account. Things like might also trigger filters, as might using your own address, but the system knowing for sure it didn’t come from inside.

    For your loggers I would personally choose something like

      1. smtp2go can send attachments if sent directly from their webpage, but I am not sure if it is possible with a client program, at least I have nevr come across anybody doing it.
        Sorry I couldn’t give you a more desirable answer

      2. SMTP is just a mechanism to transport mail. It has no clue about the content. If you want to send and image you need to format the message as a Mime message. It’s too complicated to explain here, but in essence the message is cut up in it’s components using unique headers and footers and some additional information per component telling what type of component (image, file, html, plain text, etc) it is. Here is an introduction:

  2. Thanks Jeroen, you are right and actually have done that in the past (with visual basic and also IIS I think), and refer to that in the beginning, but found that several receiving mailservers apparently didnt accept such incoming mails, as they didnt see the correct maildomainas originator.
    Though it is an extra step, SMTP2GO is easier to implement for the average user who just wants to send a mail without having to mess too much with smtp settings. I must admit for me it was a step as my slightly anal retentive character finds direct use of my google mailserver the more ‘correct’ way to go

  3. This worked like a charm! Truly grateful for this as your code is not too complex to understand for a beginner – thank you good sir!

  4. Worked first time for me too! It’s actually my first ESP8266 app uploaded in Arduino directly (I tried a sensor reading example in B4R a few days ago, that also worked). Not far off my first Arduino app either.

    I’m not a newbie, I’m actually a hardware / embedded engineer and have been doing these sorts of things for decades. I’m no stranger to SMTP either. What I find really astounding though, is that an NZ$3 “micro” can email me all on its ownsome, after I lift some code off the web (this site!), make some quick mods without really understanding what I am doing, plug in the board, and upload – and in pops the email telling me its supply voltage and Device ID.

    So thanks for providing this useful sample that “just worked”!

  5. Hey bro, why i failed send the email??

    WiFi Connected
    220 ESMTP Exim 4.87 Sat, 01 Jul 2017 06:33:30 +0000
    Sending EHLO Hello []
    250-SIZE 52428800
    250 HELP
    Sending auth login
    334 VXNlcm5hbWU6
    Sending User
    334 UGFzc3dvcmQ6
    Sending Password
    535 Incorrect authentication data

    1. it looks like you are sending the wrong log in codes. Have you converted them to base64?
      I presume you did but maybe made a mistake there?
      It also may help to allow 3rd party access in google

    2. 530 5.7.0 Must issue a STARTTLS command first. l22sm9788537wmi.39 – gsmtp
      i am getting this error
      can anyone help to sort it out

  6. Hi, I managed to get the sketch going. Looking at the serial monitor everything looks ok but I’m getting no email.
    Here’s my serial monitor output:

    WiFi Connected
    220 ESMTP Exim 4.87 Wed, 12 Jul 2017 19:46:24 +0000
    Sending EHLO Hello [x.x.x.x]
    250-SIZE 52428800
    250 HELP
    Sending auth login
    334 VXNlcm5hbWU6
    Sending User
    334 UGFzc3dvcmQ6
    Sending Password
    235 Authentication succeeded
    Sending From
    250 OK
    Sending To
    250 Accepted
    Sending DATA
    354 Enter message, ending with “.” on a line by itself
    Sending email
    Voltage2704250 OK id=1dVNak-4gfFQh-CO
    Sending QUIT
    221 closing connection

    What could I be doing wrong ?

    Thanks in advance !

    1. Indeed, according to the serial output it should have been sent. The only thing i can think of is that perhaps the “mail to” address is different than you expect.
      It has been a while since i used this program but if you use gmail i think gmail stores the sent mail. Can you check if the mail is in your sent box?

      If not can you you try and decode the mail to address again

      1. Stupid, stupid me !! 😁
        Stuff’s in my spam box….
        You put me on the right track ! Thanks very much 😊

        So it’s working. Let the fun begin !!!!

      2. hello how to get the ehlo ip adresss and what does it mean???huhuhu
        Serial.println(F(“Sending hello”));
        // change to the IP of your Arduino
        if(!eRcv()) return 0;
        this is juz example…where to get ehlo ip address and whats the meaning change to the ip of your arduino??

      3. The EHLO command has nothing to do with an IP address, it is a command telling the system to use the extended hello protocol. Described here:
        The piece of code you use as example is not from me so I probably am not the right person to ask about it’s intricacies, but I presume the ‘ip address of the arduino’ is the internal address of your Arduino in your network. Usually those all start with 192.168

  7. Hello,
    Is there a way to send email to more than one recipient ? If so can you please share it with me ?

    1. I think it is client.println(F("RCPT To:;;"));

    2. That might work, but the correct way is simply repeating the RCPT TO command. Each should answer 250 OK.

      1. When I modified the original mail program for ESP32 I modified the sketch, .cpp and the .h file to allow for the creation of an array of recipient addresses. You could then send the number of addresses in the array and pass the array as part of the Send function

  8. Thank you for the sample program. I am trying to troubleshoot an error code. Are error codes generated in a linear fashion (i.e. generated from the line’s of code that are subsequent to the prior Serial.print statement? If so I’m having trouble with the statement
    client.println(F(“RCPT To:“)); and getting the error code
    “550 that smtp username’s account is not allowed to send”

    I replaced the with known good addresses, one at comcast, the other at gmail. It appears that there are two locations where the target email location is identified. Once is in –
    client.println(F(“RCPT To:“)); and the other in –
    client.println(F(“To:“)); // change to your address
    Obviously it works according to the other commenters – so it must be okay. Any help would be appreciated. Thanks!

    1. Craig, it has been a while since I have looked at this program, so I have to reacquaint myself with it again, but I guess the most plausible reason is that Gmail has tigthened its security and now in your settings you have to indicate whether you allow 3rd party applications to use your account.
      Try that and let me know if it that solves yr problem 🙂

      1. Yes, I think your guess is correct – but I’m still working on it. The SMTP2Go support folks (really very helpful) have indicated that GMail, as you said, has disallowed 3rd parties from generating emails on the GMail system. This was true even after I lowered my security threshold on the GMail security settings. But since then I have found, and I offer to this forum, that one can make a direct connection from an ESP8266 device to multiple IFTTT maker “Applets” that enable SMS messages, emails (to, but not from GMail), and even phone calls. Hours ago, I successfully tested all three modes via a URL short-cut and am now attempting to code it into an ESP8266.

        Your code was a fantastic point of beginning for my rookie origin, and I thank you again. I hope this record is useful to others. Keep up the good work spreading the knowledge!

      2. Thanks for your kind words. Seems then that Google became even more restrictive since I last used this.
        IFTTT indeed offers many applets for all sorts of tasks. Beware though that sometimes these applets don’t react immediately.
        Playback also read my reaction to Jeroen, as I still send 3rd party mail through gmail

    2. I never have a problem using google SMTP services for dispatching email, but you do have to follow their rules. It depends on the sort of subscription (I am assuming a free one in the rest of this comment. Note that things are different for business accounts and you may easily end up in the wrong help documents) and you have to be able to support SSL, which above code does not. As google requires you to authenticate when using their mail gateway, using a non SSL connection is just not right. I am with google on this one. I also assume you are using two step authentication on the google account, as not doing so in this time is just not a smart thing to do. Two step authentication for the browser services changed google’s behavior somewhat for the SMTP gateway.

      – you need to use as your mail relay host
      – you need to use SSL and port 465.
      – because of Two Step, you need to create a separate password for this in your google settings.

      After this, google will work and even allow the “From” to be something different than your gmail address, something other providers often do no allow.

      If ssl is a total stumbling block, I would NOT recommend providing a public service. Misuse is lurking and providers like these are easily blocked in anti-spam lists. A better option then is to not use authentication at all and use your Internet provider’s SMTP server. They almost always allow this (only) from within their network.

      Personally, I have created a separate google account for just & all my home automation stuff. It is used for exactly this, and it’s the login for the old android phones I use as displays-controllers. It really all works as a charm.

      1. I’d like to chime in and respectfully ‘kinda disagree’ with the need for encryption in all cases. I’ve written on this before criticising some knee-jerk reactions from providers. While the internets is getting a lot more encryption on mail delivery and Google seems to be leading the charge, it’s not ubiquitous, last I checked it wasn’t even up to 50% (I assume it is over that level now). For an app like this that is always going to be connected via a private connection, I can’t see how it really matters, especially if it’s a dedicated mail account and it is just some non-critical monitoring.

        Encrypted mail is essential on public wifi, reading plaintext authentication is near trivial, where doing this to someone’s private connection is near impossible and has been for decades.

        People do need to be very careful though, as any path to open email is like gold to spammers these days. I’m just saying there are much easier ways to get around the problem (for them) than hacking a private connection, rendering encryption moot in nearly all practical cases. If Google want to guarantee a link for delivery to their servers then good on them.

      2. Thanks Jeroen. Though I have not used the program as such for a long time, I realise that I gave a camera that sends mails via Google and my OpenHAB application is sending mails, so indeed 3rd party email still possible

      3. Antony, you are of course free to disagree. But my point was not about encrypting email *content* (though my personal opinion is it is very wise to encrypt at least the transport, and possibly the storage too), but about the authentication sequence, needed for anything but your ISP’s relay, and sometimes even that one.

      4. E: I am pretty sure for both the camera and OpenHab you then used the settings I described above. SSL is near always baked into these devices and AFAIK Google does not accept anything else. For an Arduino, for all intents and purposes SSL is too much heavy lifting, and for an ESP8266 it takes a significant chunk out of it’s resources.

      5. Yes indeed, those are more or less the standard settings. That and scaling down the protection on Gmail to accept 3rd party apps

      6. I must admit to being a bit behind the play. I had never really considered the (presumably hypothetical) situation of authenticating in a secure way then not caring about the content. My ISP required authenticating years before encryption. That was to simplify the support problem of people being unable to send via another network, say from a hotel, so they added authentication to make this possible – of course creating a security hole (but that wasn’t their concern, it was complaining customers). It was only fairly recently they enforced encryption, then got all evangelical about it by refusing to send emails themselves while blocking port 25 (basically said “use Gmail”). Considering your point now, I can see just how cart before the horse my ISP’s behaviour was, well before it got my ire up.

        I haven’t dug into the encryption capabilities of the ESP8266, and hadn’t worked out one way or the other whether it can work for email. From what you’re saying it sounds like it could, using SSL from the start or inserting a STARTTLS into the logon sequence in the code above.

        For me doing something like sending the battery voltage from my car, I am happy enough to grit my teeth and trust my ISP and SMTP2GO (who are also local) to not steal their own account and send spam from it. For now at least.

  9. ‘535 Incorrect authentication data’ problem solved.
    This may help others who seem to have the above problem. I lost a day trying to match the Username and Password at the SMTP2GO site with the UN and PW in my code. Wrong. The UN and PW in the ESP code should be the 64 bit encoded version of the UN and PW listed in my account at SMTP2GO/Settings/User page. So while not exact copies, the ESP and SMTP2GO platforms’ UN and PW are related via encoding. Hope it helps you!

  10. I forgot to mention: they support people at SMTP2GO are very patient and helpful. While my current limited use is free, I will look for any opportunity to do business with them.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: