ESP8266 NodeMCU Send Emails using an SMTP Server: HTML, Text, and Attachments (Arduino)

In this tutorial, you’ll learn how to send emails with the ESP8266 NodeMCU board using an SMTP server. We’ll show how to send an email with raw text, HTML text, and how to send attachments like images and files (.txt). We’ll program the ESP8266 NodeMCU board with the Arduino core.

ESP8266 NodeMCU Send Emails using an SMTP Server HTML Text and Attachments Arduino IDE

In this tutorial, we cover the following topics:

We have a similar tutorial for the ESP32 board: ESP32 Send Emails using an SMTP Server: HTML, Text, and Attachments (Arduino IDE)

Introducing SMTP Servers

SMTP means Simple Mail Transfer Protocol and it is an internet standard for email transmission. To send emails using an ESP8266, you need to connect it to an SMTP Server.

ESP-Mail-Client Library

To send emails with the ESP8266 NodeMCU board, we’ll use the ESP-Mail-Client library. This library allows the ESP8266 to send and receive emails with or without attachments via SMTP and IMAP servers. If you like this library and you’ll use it in your projects, consider supporting the developer’s work—see the library GitHub page.

In this tutorial, we’ll use SMTP to send an email with and without attachments. As an example, we’ll send an image (.png) and a text (.txt) file. The files to be sent via email can be saved in the ESP8266 Filesystem (SPIFFS or LittleFS) or in a microSD card (not covered in this tutorial).

Installing the ESP-Mail-Client Library

Before proceeding with this tutorial, you need to install the ESP-Mail-Client library. This library is not available to install through the Arduino IDE Library Manager. Follow the next steps to install the library:

  1. Click here to download ESP-Mail-Client library .zip folder.
  2. In your Arduino IDE, go to Sketch > Include Library > Add .ZIP Library.
  3. Select the .zip file you’ve just downloaded.

Then, if you go to File > Examples > ESP-Mail-Client, you’ll find several examples that you can try. You can also access the examples in the library GitHub page—here.

If you’re using the ESP8266 with VS Code + PlatformIO, you should copy the following to your platformio.ini file to include the library.

lib_deps = mobizt/ESP Mail Client @ ^1.1.7

Sender Email (New Account)

We recommend creating a new email account to send the emails to your main personal email address. Do not use your main personal email to send emails via ESP8266. If something goes wrong in your code or if you make too many requests by mistake, you can be banned or have your account temporarily disabled.

We’ll use a newly created Gmail.com account to send the emails, but you can use any other email provider. The receiver email can be your personal email without any problem.

Create a Sender Email Account

Create a new email account for sending emails with the ESP8266. If you want to use a Gmail account, go to this link to create a new one.

Gmail Create a new account

Create an App Password

You need to create an app password so that the ESP32 is able to send emails using your Gmail account. An App Password is a 16-digit passcode that gives a less secure app or device permission to access your Google Account. Learn more about sign-in with app passwords here.

An app password can only be used with accounts that have 2-step verification turned on.

  1. Open your Google Account.
  2. In the navigation panel, select Security.
  3. Under “Signing in to Google,” select 2-Step Verification > Get started.
  4. Follow the on-screen steps.

After enabling 2-step verification, you can create an app password.

  1. Open your Google Account.
  2. In the navigation panel, select Security.
  3. Under “Signing in to Google,” select App Passwords.
Create app password gmail
  1. In the Select app field, choose mail. For the device, select Other and give it a name, for example ESP32. Then, click on Generate. It will pop-up a window with a password that you’ll use with the ESP32 or ESP8266 to send emails. Save that password (even though it says you won’t need to remember it) because you’ll need it later.
Generated App password gmail

Now, you should have an app password that you’ll use on the ESP32 code to send the emails.

Gmail app password created for ESP8266 send emails

If you’re using another email provider, check how to create an app password. You should be able to find the instructions with a quick google search “your_email_provider + create app password”.

Gmail SMTP Server Settings

If you’re using a Gmail account, these are the SMTP Server details:

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

Outlook SMTP Server Settings

For Outlook accounts, these are the SMTP Server settings:

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

Live or Hotmail SMTP Server Settings

For Live or Hotmail accounts, these are the SMTP Server settings:

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

If you’re using another email provider, you need to search for its SMTP Server settings. Now, you have everything ready to start sending emails with your ESP8266.

In your Arduino IDE, you can go to File > Examples > ESP-Mail-Client and experiment with the examples provided—you need to insert your email details (sender and recipient accounts), the SMTP server settings, and your SSID and password.


Send an Email with HTML or Raw Text with ESP8266

The following code sends an email via SMTP Server with HTML or raw text. As an example, the ESP8266 sends an email once when it boots. Then, you should be able to modify the code and integrate it into your own projects.

Don’t upload the code yet, you need to make some modifications to make it work for you.

/*
  Rui Santos
  Complete project details at:
   - ESP32: https://RandomNerdTutorials.com/esp32-send-email-smtp-server-arduino-ide/
   - ESP8266: https://RandomNerdTutorials.com/esp8266-nodemcu-send-email-smtp-server-arduino/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  Example adapted from: https://github.com/mobizt/ESP-Mail-Client
*/

// To send Emails using Gmail on port 465 (SSL), you need to create an app password: https://support.google.com/accounts/answer/185833

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

#define WIFI_SSID "REPLACE_WITH_YOUR_SSID"
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD"

#define SMTP_HOST "smtp.gmail.com"
#define SMTP_PORT 465

/* The sign in credentials */
#define AUTHOR_EMAIL "[email protected]"
#define AUTHOR_PASSWORD "YOUR_EMAIL_PASS"

/* Recipient's email*/
#define RECIPIENT_EMAIL "[email protected]"

/* 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(){
  Serial.begin(115200);
  Serial.println();
  Serial.print("Connecting to AP");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED){
    Serial.print(".");
    delay(200);
  }
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.println();

  /** Enable the debug via Serial port
   * none debug or 0
   * basic debug or 1
  */
  smtp.debug(1);

  /* Set the callback function to get the sending results */
  smtp.callback(smtpCallback);

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

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

  /* Declare the message class */
  SMTP_Message message;

  /* Set the message headers */
  message.sender.name = "ESP";
  message.sender.email = AUTHOR_EMAIL;
  message.subject = "ESP Test Email";
  message.addRecipient("Sara", RECIPIENT_EMAIL);

  /*Send HTML message*/
  String htmlMsg = "<div style=\"color:#2f4468;\"><h1>Hello World!</h1><p>- Sent from ESP board</p></div>";
  message.html.content = htmlMsg.c_str();
  message.html.content = htmlMsg.c_str();
  message.text.charSet = "us-ascii";
  message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit;

  /*
  //Send raw text message
  String textMsg = "Hello World! - Sent from ESP board";
  message.text.content = textMsg.c_str();
  message.text.charSet = "us-ascii";
  message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit;
  
  message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low;
  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: <[email protected]>");

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

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

void loop(){

}

/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status){
  /* Print the current status */
  Serial.println(status.info());

  /* Print the sending result */
  if (status.success()){
    Serial.println("----------------");
    ESP_MAIL_PRINTF("Message sent success: %d\n", status.completedCount());
    ESP_MAIL_PRINTF("Message sent failled: %d\n", status.failedCount());
    Serial.println("----------------\n");
    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.c_str());
      ESP_MAIL_PRINTF("Subject: %s\n", result.subject.c_str());
    }
    Serial.println("----------------\n");
  }
}

View raw code

You need to insert your network credentials, as well as setting the sender email, SMTP Server details, recipient, and message.

How the Code Works

This code is adapted from an example provided by the library. The example is well commented so that you understand what each line of code does. Let’s just take a look at the relevant parts that you need or may need to change.

First, insert your network credentials in the following lines:

#define WIFI_SSID "REPLACE_WITH_YOUR_SSID"
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD"

Insert your SMTP server settings. If you’re using a Gmail account to send the emails, these are the settings:

#define SMTP_HOST "smtp.gmail.com"
#define SMTP_PORT 465

Insert the sender email sign in credentials (complete email and APP password you created previously)

#define AUTHOR_EMAIL "[email protected]"
#define AUTHOR_PASSWORD "YOUR_EMAIL_PASS"

Insert the recipient email:

#define RECIPIENT_EMAIL "[email protected]"

Set the message headers in the following lines in the setup()—sender name, sender email, email subject, and the recipient name and email:

/* Set the message headers */
message.sender.name = "ESP";
message.sender.email = AUTHOR_EMAIL;
message.subject = "ESP Test Email";
message.addRecipient("Sara", RECIPIENT_EMAIL);

In the following lines, set the content of the message (raw text) in the textMsg variable:

//Send raw text message
String textMsg = "Hello World! - Sent from ESP board";
message.text.content = textMsg.c_str();
message.text.charSet = "us-ascii";
message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit;

If you want to send HTML text instead, uncomment the following lines— you should insert your HTML text in the htmlMsg variable.

/*Send HTML message*/
/*String htmlMsg = "<div style=\"color:#2f4468;\"><h1>Hello World!</h1><p>- Sent from ESP board</p></div>";
message.html.content = htmlMsg.c_str();
message.html.content = htmlMsg.c_str();
message.text.charSet = "us-ascii";
message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit;*/

Finally, the following lines send the message:

if (!MailClient.sendMail(&smtp, &message))
    Serial.println("Error sending Email, " + smtp.errorReason());

Demonstration

Upload the code to your ESP8266. After uploading, open the Serial Monitor at a baud rate of 115200.

If everything goes as expected you should get a similar message in the Serial Monitor.

ESP8266 NodeMCU Send Email Message Successfully Serial Monitor

Check your email account. You should have received an email from your ESP8266 board.

Email received from ESP8266 Board Gmail Account

If you set the option to send a message with HTML text, this is how the message looks like:

ESP8266 SMTP Server Send Email with Body HTML text format

If you’ve enable the raw text message, this is the email that you should receive.

ESP8266 SMTP Server Send Email with Body raw text format

Send Attachments via Email with ESP8266 (Arduino IDE)

This section will show you how to send attachments in your emails sent by the ESP8266. We’ll show you how to send .txt files or pictures. This can be useful to send a .txt file with sensor readings from the past few hours or other applications.

You should save the files you want to send in the ESP8266 filesystem (SPIFFS or LittleFS). You can also send attachments saved on a microSD card, but we’ll not cover this subject in this tutorial.

Setting the Filesystem

To send files via email, you should save them in the ESP8266 filesystem. You can use SPIFFS or LittleFS. To upload files to the filesystem using Arduino IDE, you need to install a Filesystem Uploader Plugin. Read one of the following tutorials and install the plugin depending on the filesystem you want to use:

If you’re using VS Code + PlatformIO, follow the next tutorial to learn how to upload files to LittleFS:

IMPORTANT

Note: To use LittleFS with the ESP-Mail-Client library, you need to edit the library files (ESP_Mail_FS.h) to use that specific filesystem. Read the following section if you want to use LittleFS. Otherwise, skip to this section.

Edit the Library Files to use LittleFS

The default filesystem used by the ESP-Mail-Client library is SPIFFS. If you want to use SPIFFS, you can skip this section. Otherwise, continue reading to learn how to edit the library to use LittleFS instead.

To use LittleFS, you must edit the ESP_Mail_FS.h file.

Go to your Arduino installation Libraries folder. In my case, it is located in the following path (yours may be similar):

C:\Users\USERNAME\Documents\Arduino\libraries

Go to ESP-Mail-Client-master > src and open the ESP_Mail_FS.h file with a text editor.

Locate the following section.

ESP-Mail-Client Library Change Filesystem

Replace it with the following:

#if defined(ESP32)
  #define ESP_Mail_DEFAULT_FLASH_FS SPIFFS
#endif

#if defined(ESP8266)
  #include <LittleFS.h>
  #define ESP_Mail_DEFAULT_FLASH_FS LittleFS
#endif

This way, it uses SPIFFS filesystem by default for the ESP32 and LittleFS for the ESP8266.

ESP-Mail-Client Change Filesystem ESP32 and ESP8266

Save the file. Now the library will use LittleFS as the default filesystem for the ESP8266.

Upload Files to the Filesystem

Create a new Arduino sketch and save it. Go to Sketch > Show Sketch folder. Inside the Arduino sketch folder, create a folder called data. Move a .png file and .txt file to your data folder.

Alternatively, you can click here to download the project folder.

Note: with the default code, your files must be named image.png and text_file.txt or you can modify the code to import files with a different name.

We’ll be sending these files:

Upload the files to filesystem to send as an email attachment

Your folder structure should look as follows (download project folder):

Send email attachments folder structure filesystem organizing files

After moving the files to the data folder, in your Arduino IDE, go to Tools ESP8266 Sketch Data Upload or ESP8266 LittleFS Data Upload depending on the filesystem and wait for the files to be uploaded.

ESP8266 Tools LittleFS Data Upload Arduino IDE

You should get a success message on the debugging window. If the files were successfully uploaded, move on to the next section.

SPIFFS image done uploading success message

Code

The following code sends an email with a .txt file and a picture attached. Before uploading the code, make sure you insert your sender email settings as well as your recipient email.

/*
  Rui Santos
  Complete project details at:
   - ESP8266: https://RandomNerdTutorials.com/esp8266-nodemcu-send-email-smtp-server-arduino/
   
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  Example adapted K. Suwatchai (Mobizt): https://github.com/mobizt/ESP-Mail-Client Copyright (c) 2021 mobizt
*/

// To send Emails using Gmail on port 465 (SSL), you need to create an app password: https://support.google.com/accounts/answer/185833
// The file systems for flash and sd memory can be changed in ESP_Mail_FS.h.

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP_Mail_Client.h>

#define WIFI_SSID "REPLACE_WITH_YOUR_SSID"
#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD"

#define SMTP_HOST "smtp.gmail.com"

/** 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 465

/* The log in credentials */
#define AUTHOR_EMAIL "[email protected]"
#define AUTHOR_PASSWORD "YOUR_EMAIL_PASS"

/* Recipient's email*/
#define RECIPIENT_EMAIL "[email protected]"
/* 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(){
  Serial.begin(115200);
  Serial.println();
  Serial.print("Connecting to AP");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED){
    Serial.print(".");
    delay(200);
  }
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.println();

  if (!LittleFS.begin()) {
  // Uncomment to use SPIFFS
  //if (!SPIFFS.begin()) {
    Serial.println("An error has occurred while mounting the filesystem");
  }
  else{
    Serial.println("Filesystem mounted successfully");
  }

  /** Enable the debug via Serial port
   * none debug or 0
   * basic debug or 1
  */
  smtp.debug(1);

  /* Set the callback function to get the sending results */
  smtp.callback(smtpCallback);

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

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

  /* Declare the message class */
  SMTP_Message message;

  /* Enable the chunked data transfer with pipelining for large message if server supported */
  message.enable.chunking = true;

  /* Set the message headers */
  message.sender.name = "ESP";
  message.sender.email = AUTHOR_EMAIL;

  message.subject = "Email with attachments";
  message.addRecipient("Sara", RECIPIENT_EMAIL);

  String htmlMsg = "This message contains attachments: image and text file.";
  message.html.content = htmlMsg.c_str();
  message.html.charSet = "utf-8";
  message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp;

  message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal;
  message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay;

  /* The attachment data item */
  SMTP_Attachment att;

  /** Set the attachment info e.g. 
   * file name, MIME type, file path, file storage type,
   * transfer encoding and content encoding
  */
  att.descr.filename = "image.png";
  att.descr.mime = "image/png"; 
  att.file.path = "/image.png";
  att.file.storage_type = esp_mail_file_storage_type_flash;
  att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;

  /* Add attachment to the message */
  message.addAttachment(att);

  message.resetAttachItem(att);
  att.descr.filename = "text_file.txt";
  att.descr.mime = "text/plain";
  att.file.path = "/text_file.txt";
  att.file.storage_type = esp_mail_file_storage_type_flash;
  att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;

  /* Add attachment to the message */
  message.addAttachment(att);

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

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

void loop(){
}

/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status){
  /* Print the current status */
  Serial.println(status.info());

  /* Print the sending result */
  if (status.success()){
    Serial.println("----------------");
    ESP_MAIL_PRINTF("Message sent success: %d\n", status.completedCount());
    ESP_MAIL_PRINTF("Message sent failled: %d\n", status.failedCount());
    Serial.println("----------------\n");
    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);
    }
    Serial.println("----------------\n");
  }
}

View raw code

How the code works

This code is very similar to the previous one, so we’ll just take a look at the relevant parts to send attachments.

In the setup(), you need to initialize the filesystem: SPIFFS or LittleFS.

if (!LittleFS.begin()) {
// Uncomment to use SPIFFS
//if (!SPIFFS.begin()) {
  Serial.println("An error has occurred while mounting the filesystem");
}
else{
  Serial.println("Filesystem mounted successfully");
}

You need to create an attachment as follows:

/* The attachment data item */
SMTP_Attachment att;

Then, add the attachment details: filename, MIME type, file path, file storage type, and transfer encoding. In the following lines, we’re sending the image file.

att.descr.filename = "image.png";
att.descr.mime = "image/png"; 
att.file.path = "/image.png";
att.file.storage_type = esp_mail_file_storage_type_flash;
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;

Finally, add the attachment to the message:

message.addAttachment(att);

If you want to send more attachments, you need to call the following line after adding the previous attachment:

message.resetAttachItem(att);

Then, enter the details of the other attachment (text file):

att.descr.filename = "text_file.txt";
att.descr.mime = "text/plain";
att.file.path = "/text_file.txt";
att.file.storage_type = esp_mail_file_storage_type_flash;
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;

And add this attachment to the message:

message.addAttachment(att);

Finally, you just need to send the message as you did with the previous example:

if (!MailClient.sendMail(&smtp, &message, true))
  Serial.println("Error sending Email, " + smtp.errorReason());

Demonstration

After uploading the code, open the Serial Monitor at a baud rate of 115200. If everything goes as expected, you should get a similar message on the Serial Monitor.

ESP8266 NodeMCU Send Email Message Successfully Serial Monitor

If you go to your inbox, you should get the message with the two attachments:

Send Email with Attachments ESP8266 NodeMCU Gmail Account Arduino IDE

Wrapping Up

In this tutorial, you’ve learned how to send emails with the ESP8266 NodeMCU board using an SMTP Server. You’ve learned how to send HTM text, raw text, and attachments.

Now, the idea is to modify the code and include it in your own projects. For example, it can be useful to send a .txt file with the sensor readings of the last hour, notifications when motion is detected, and much more.

We hope you’ve find this tutorial interesting. We have a similar guide for the ESP32:

Learn more about the ESP8266 with our resources:

Thanks for reading.



Build Web Server projects with the ESP32 and ESP8266 boards to control outputs and monitor sensors remotely. Learn HTML, CSS, JavaScript and client-server communication protocols DOWNLOAD »

Build Web Server projects with the ESP32 and ESP8266 boards to control outputs and monitor sensors remotely. Learn HTML, CSS, JavaScript and client-server communication protocols DOWNLOAD »


Enjoyed this project? Stay updated by subscribing our newsletter!

76 thoughts on “ESP8266 NodeMCU Send Emails using an SMTP Server: HTML, Text, and Attachments (Arduino)”

  1. Thank you so much for sharing this fantastic tutorial and for including step-by-step instructions on how to understand the concept and how the project works.

    Reply
  2. Hi Sara,
    It is beside the point, but what it is the correct address for forum.
    I want to find help for one of my problem or put a question
    Thank you
    Ion

    Reply
  3. I had a problem compiling the original version of this sketch with the following includes:
    #include <Arduino.h>
    #if defined(ESP32)
    #include <WiFi.h>
    #elif defined(ESP8266)
    #include <ESP8266WiFi.h>
    #include <FS.h>
    #include <SD.h>
    #endif
    #include <ESP_Mail_Client.h>

    I also got errors on all of my older sketches some of which have been in use since 2018. After a great deal of research I found the answer to the compiler error. (Unable to compile for this device.) All of the offending sketches had included the SD.h library. The solution is to simply rename a folder. Change this:
    C:\Users\\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.0\libraries\ESP8266SdFat
    to this:
    C:\Users\\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.0\libraries\SdFat
    Remove the ESP8266 from the folder name for SdFat
    I was wary about renaming the folder so I made a copy and renamed that. Now all of my ESP8266 sketches compile without errors.

    Reply
  4. Sara,
    I have RCWL motion sensors that when triggered need to send a notification. The sensors use NRF24 on Arduino and send to and esp8266 (that collects from 5 NRF24) the signal and then thru wifi to Telegram. Works fine , but. I wanted to use email notifications. I could not figure out how to pass the sensors arguments, data[0] data[1] etc to the HTML email. The html email works with “text” just fine. Can you help?

    Reply
  5. Hi,
    I keep getting this error.
    C:\Users\Pertti\Documents\Arduino\libraries\ESP-Mail-Client-master\src/wcs/esp8266/ESP8266_WCS.h:34:29: fatal error: bearssl/bearssl.h: No such file or directory
    #include <bearssl/bearssl.h>
    What should I do?

    Reply
  6. I tried to use it but I can’t send mail .My error is: “set recipient failed”. I know that my mail address is active. Mail which I send uses raw txt. SMTP server is active and mailbox is ready to send mails. I’m using local webserver host (home.pl), port 587. What do I do wrong?

    Reply
      • Yea! I found it by myself. I disabled:
        message.priority and message.response.notify and now mails ESP can send to smtp server. I’ve noticed that, if ESP has no wifii connection, esp crashed. So I changed sketch to disable smtp sending when wifi is off.
        I changed String massage, to const PROGMEM char. It doesn’t use RAM. All smtp configuratios are stored in flash. Mail are sent only when esp started (info mail on my mailbox) and when temperature is lower than 0 degree Celcius(or higher than 30) to my family. So it happens one’s a day, maybe less. But it works.

        Reply
      • Yea! I found it by myself. I disabled:
        message.priority and message.response.notify and now mails ESP can send to smtp server. I’ve noticed that, if ESP has no wifii connection, esp crashed. So I changed sketch to disable smtp sending when wifi is off.
        I changed String massage, to const PROGMEM char. It doesn’t use RAM. All smtp configuratios are stored in flash. Mail are sent only when esp started (info mail on my mailbox) and when temperature is lower than 0 degree Celcius(or higher than 30) to my family. So it happens one’s a day, maybe less. But it works.

        Reply
  7. Hi Sara,

    I’m trying to use this sketch to monitor my house’s electrical system. If the mains power fails, I wish to be notified by email.
    The router and the Esp8266 are on UPS so that they continue to work in the event of a power failure.
    How do I call the routine for sending the email at the moment of a power failure ?
    I have tried this, but it doesn’t work:
    void loop(){
    int spanning = digitalRead (D1);
    if (spanning == LOW) {MailClient.sendMail(&smtp, &message);}
    Serial.println (spanning);
    }

    Reply
  8. Hi,
    This works great and I appreciate your instruction.
    I would like to insert a conditional statement controlling the actual sending of the mail.
    For instance, I would like the email sent when a sensor is activated.
    I tried inserting in several places, but was unable to get it to work.
    Can you help me out?
    Thanks in advance,
    Mike

    Reply
  9. I get this error every time. I’ve tried changing the recipient e-mail address, but it doesn’t matter. What’s going on?

    Sending message header…

    C: send message header
    < S: 250 2.1.0 Sender OK
    < S: 501 5.5.4 Invalid arguments
    Error, set recipient failed
    E: set recipient failed
    Error sending Email, set recipient failed

    Reply
  10. Boa noite, só uma duvida rápida. Já tentou fazer o envio do arquivo (TXT e foto) armazenado em um cartão SD, se tiver realizado essa programação, poderia dar uma dica de como puxar o arquivo do SD em vez de carregar o TXT guardado dentro do esp. Acredito que as atualizações feitas dentro da biblioteca não seriam validas para o uso no caso de SDcard.

    Reply
    • Boa tarde.
      Acho que é só trocar o modo de armazenamento de esp_mail_file_storage_type_flash para esp_mail_file_storage_type_sd.
      Sei que na altura experimentei, mas por qualquer motivo não consegui pôr a funcionar.
      Cumprimentos.
      Sara Santos

      Reply
  11. I have behavior I don’t understand. When I call:
    if (!MailClient.sendMail(&smtp, &message)) Serial.println(“Error sending Email, ” + smtp.errorReason());
    The first time I call it I get a single email sent, as expected.
    The second time I call it, it spawns two emails. The next time it sends 3 emails. and so on.
    Any idea why?

    Also what is “Sara” for in this line: message.addRecipient(“Sara”, RECIPIENT_EMAIL);
    I don’t see it anywhere in the received email.

    Thanks

    Reply
  12. Great tutorial. Regarding Gmails Less sure app, If I enable 2 step verification and replace my old regular Gmail password with the new APP PASSWORD as you described, then Gmail will continue to allow the esp8266 to send emails long after Gmail discontinues less secure apps…Right? Just want to make sure.

    Reply
  13. Yes, that is what I need. The program says, that it is sent, but I don’t receive any mails. I get a response
    13:17:15.020 -> Closing the session…
    13:17:15.020 -> > C: terminate the SMTP session
    13:17:15.020 ->
    13:17:15.020 -> Message sent successfully
    13:17:15.074 -> > C: Message sent successfully
    13:17:15.074 ->
    13:17:15.074 -> —————-
    13:17:15.074 -> Message sent success: 1
    13:17:15.074 -> Message sent failled: 0
    13:17:15.074 -> —————-
    13:17:15.074 ->
    13:17:15.074 -> Message No: 1
    13:17:15.074 -> Status: success
    13:17:15.074 -> Date/Time: 1970/1/1 0:0:6
    13:17:15.074 -> Recipient: ⸮R⸮?
    13:17:15.074 -> Subject: ⸮R⸮?
    13:17:15.074 -> —————-

    The recipient is somehow encrypted. And also the subject. But also in the sent-folder of gmail it can be seen as successful mail. Hmm!?!
    Do you have any idea what is going wrong?

    Reply
    • Hooray, I got the emails.
      It works fine, although I don’t know why the recipient and subject aren’t showing.

      Our IT department filtered out the mail – I received it one day later as “inbound quarantined emails”.

      Great software, thank you for the detailed explanation.

      Reply
  14. Hello Sara & Rui,

    I am trying to run your example sketch and it will not compile.
    It seems to be having a problem with the ESP_MAIL_PRINTF line stating:
    cannot pass objects of non-trivially-copyable type ‘class MB_String’ through ‘…’
    However, I’m not sure that error statement refers to the PRINTF.
    Here is the entire error message:
    Arduino: 1.8.19 (Windows Store 1.8.57.0) (Windows 10), Board: “NodeMCU 1.0 (ESP-12E Module), 80 MHz, Flash, Disabled (new can abort), All SSL ciphers (most compatible), 4MB (FS:2MB OTA:~1019KB), 2, v1.4 Higher Bandwidth, Disabled, None, Only Sketch, 115200”

    In file included from C:\Users\Glenn\Documents\Arduino\libraries\ESP_Mail_Client\src/wcs/esp8266/ESP8266_TCP_Client.h:47:0,
    from C:\Users\Glenn\Documents\Arduino\libraries\ESP_Mail_Client\src/wcs/ESP_TCP_Clients.h:33,
    from C:\Users\Glenn\Documents\Arduino\libraries\ESP_Mail_Client\src/ESP_Mail_Client.h:99,
    from C:\NodeMCU Projects\Examples\ESP8266_Email_Web_Server_Example\ESP8266_Email_Web_Server_Example.ino:20:
    C:\Users\Glenn\Documents\Arduino\libraries\ESP_Mail_Client\src/./wcs/base/TCP_Client_Base.h: In member function ‘int TCP_Client_Base::setTimestamp(time_t)’:
    C:\Users\Glenn\Documents\Arduino\libraries\ESP_Mail_Client\src/./wcs/base/TCP_Client_Base.h:160:24: error: variable ‘TCP_Client_Base::setTimestamp(time_t)::timeval tm’ has initializer but incomplete type
    struct timeval tm = {ts, 0}; // sec, us
    ^
    C:\Users\Glenn\Documents\Arduino\libraries\ESP_Mail_Client\src/./wcs/base/TCP_Client_Base.h:161:52: error: ‘settimeofday’ was not declared in this scope
    return settimeofday((const timeval *)&tm, 0);
    ^
    C:\NodeMCU Projects\Examples\ESP8266_Email_Web_Server_Example\ESP8266_Email_Web_Server_Example.ino: In function ‘void smtpCallback(SMTP_Status)’:

    ESP8266_Email_Web_Server_Example:139:59: error: cannot pass objects of non-trivially-copyable type ‘class MB_String’ through ‘…’

    ESP_MAIL_PRINTF("Recipient: %s\n", result.recipients);
    ^

    ESP8266_Email_Web_Server_Example:140:54: error: cannot pass objects of non-trivially-copyable type ‘class MB_String’ through ‘…’
    ESP_MAIL_PRINTF(“Subject: %s\n”, result.subject);
    ^
    Multiple libraries were found for “SD.h”
    Used: C:\Users\Glenn\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.6.3\libraries\SD
    Not used: C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.57.0_x86__mdqgnx93n4wtt\libraries\SD

    exit status 1
    cannot pass objects of non-trivially-copyable type ‘class MB_String’ through ‘…’

    This report would have more information with
    “Show verbose output during compilation”
    option enabled in File -> Preferences.

    Can you provide any guidance as to what the problem might be?

    I have used your example code with no changes except the network credentials, sender email, SMTP Server details, recipient, and message.

    Thanks,
    Glenn

    Reply
  15. Great software. I enjoy all your tutorals. I got tripped up a little on the ESP8266 not compiling because I still had old SD and SDfat libraries in my libraries folder (it’s now in the core). This might be useful for other programmers trying to use this Email client.

    Reply
  16. Great job Sara
    If you don’t mind, I see the code need some adds
    1. you may need auto reconnect if WIFI disconnects.
    2. resend if not sent successfully.
    Thanks for your great effort.

    Reply
  17. SMTP server connected, wait for greeting…
    < S: 220 smtp.gmail.com ESMTP j15-20020a056a00234f00b0052542cbff9dsm10338142pfj.99 – gsmtp

    Sending greeting response…

    C: Send SMTP command, HELO
    < S: 250-smtp.gmail.com at your service, [172.89.###.###]
    < S: 250-SIZE 35882577
    < S: 250-8BITMIME
    < S: 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH
    < S: 250-ENHANCEDSTATUSCODES
    < S: 250-PIPELINING
    < S: 250-CHUNKING
    < S: 250 SMTPUTF8
    Logging in…
    C: Send SMTP command, AUTH PLAIN
    C: ####@gmail.com
    C: ####@gmail.com ****************
    < S: 535-5.7.8 Username and Password not accepted. Learn more at
    < S: 535 5.7.8 https://support.google.com/mail/?p=BadCredentials j15-20020a056a00234f00b0052542cbff9dsm10338124pfj.99 – gsmtp
    Error, authentication failed
    E: authentication failed

    Everything works until authentication, I have app password entered.
    What do I have wrong?

    Reply
  18. Gmail has removed “less secure apps”. I have used the 2 factor and app password but Gmail wont recognize me. Is there a fix?

    Reply
      • I am using app password. When I follow it in the serial window it gets as far as “user name and password not accepted”

        Reply
        • When I initially set this up I missed setting the Sender name to the APP name matching the APP key you are using for the password. It fixed my authentication.
          /* Set the message headers */
          message.sender.name = “ESP”;

          Reply
          • I am sorry, my understanding of the code is limited. What do I need to change or replace in the code?

          • I found the problem, I hope this helps someone else. When creating the app password in google mail if you delete the app password and create a second one you MUST log out and back in before you create the new password, otherwise gmail will not recognize the new password when used to log in.

          • To get another mail recipient; Add a second line with the second email. Change it to EMAIL_1 & EMAIL_2
            reference the 2 emails on the lines “message.addRecipient” use the same name reference of EMAIL_1 & EMAIL_2

            #define RECIPIENT_EMAIL_1 “[email protected]
            #define RECIPIENT_EMAIL_2 “[email protected]” ………….add this line

            message.addRecipient(“”, RECIPIENT_EMAIL_1);
            message.addRecipient(“”, RECIPIENT_EMAIL_2); ……….add this line

  19. Does anyone know how to add a time stamp on the email message? I want to add the time an event occurs and include it with the message sent.

    Reply
    • Any of my sensors/modules with the capability of emailing also run an ntp client, which I use to accurately include the time appended to the subject. I often email to an sms gateway which are notorious for delivering the message late. With the time in the message I know when the even occurred.

      Reply
  20. Hi Sarah, hi Rui,

    realy good tutorial but i have some trouble with authentication as follow. At first, we build up a new google-account with 2nd-factor-auth and app-password as shown in tutorial.

    Our code works fine an we got a connection to SMTP-Server (SMTP-Server connected) and got greeting response. On the other side if the programm try to login we’ve got the following error:

    Application secific password required.
    Error, authentication failed
    Invalid second factor

    For login we use Server-Hostname, Server Port-Nr, Sender-Email, Sender-Name, Sender-Password and Recipient-Name & Email.

    We think, that there is a missunderstood with the login data. Should we send the second-factor password (16-digit) or should we send the email-account-password in “sender-password”? This is different and we don’t understand the usage.

    Would eb nice to get some help and feedback from you.

    Reply
    • Hi.
      The sender password is the app password.
      App passwords are used when you need to login to your account using third-party software. For example, if something goes wrong, you can delete the app password in your account, and the third-party software won’t have access to your email.
      Regards,
      Sara

      Reply
      • Sara, I believe the sender name also has to be the app name matching the app password. This was you can create multiple app passwords and google can distinguish them

        Reply
        • Hi Marty.
          The field
          AUTHOR_EMAIL refers to the sender email
          And in the AUTHOR_PASSWORD field you use the app password.
          Regards,
          Sara

          Reply
          • Thank you, Sara.
            For clarification, I stand corrected. The sender_name is not needed to complete the authentication.

  21. Hi Sara and Rui,

    another very informative tutorial. However, we use the national language German and the message text can therefore not correctly transfer all German umlauts ä, ö ü.

    Is there a solution or adjustment in the source code for this? Possibly it is the encoding enc_7bit. What exactly needs to be adjusted here?

    Thank you for a suitable solution.

    Greetings,
    Manfred

    Reply
  22. Anyone been able to send sensor values in LOOP ? For example, send a new email when there is a change of state on a digital input, say, when a door is opened then later closed. Example code would be appreciated

    Reply
    • Yes I did, Here a snippet of code. I do not explain and delete all the context, you will find out what necessary:
      code in loop:
      if (send_testmail_flag == true){
      send_mail(devicename + ” Test from Sender “, “TEST MAIL \nIP-Address: “+ WiFi.localIP().toString()+ “\n\nsent from mySensor – SW-Version ” + SWVERSION);
      send_testmail_flag = false;

      }

      function send_mail:
      String smtp_server = “smtp.gmail.com”;
      String smtp_sender = “[email protected]”;
      String smtp_port = “587”;
      String smtp_user = “[email protected]”;
      String smtp_pwd = “asdfasdfsadfasdf”;

      String smtp_ssl_port = “465”;

      void send_mail(String mysubject, String mymessage){
      check_connection(); // reconnect if wireless connection lost
      last_email_time = millis();
      smtp.debug(1);

      smtp.callback(smtpCallback); /* Set the callback function to get the sending results /
      ESP_Mail_Session session; /
      Declare the session config data */

      /* Set the session config */
      #ifdef DBG_MAIL
      Serial.println("\n *** Using default Mailserver");
      #endif
      session.server.host_name = smtp_server;
      session.server.port = smtp_ssl_port.toInt();
      session.login.email = smtp_user;
      session.login.password = smtp_pwd;
      session.login.user_domain = "";

      /* Declare the message class */
      SMTP_Message message;

      /* Set the message headers */
      message.sender.name = “MySensor”;
      message.sender.email = smtp_user;
      message.subject = mysubject;
      message.addRecipient(“myTest”, mail_address);

      //Send raw text message
      String textMsg = mymessage;
      message.text.content = textMsg.c_str();
      message.text.charSet = “us-ascii”;
      message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit;

      message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low;
      message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay;

      /* Connect to server with the session config */
      if (!smtp.connect(&session))
      //Serial.println(“—- Mail connection not successful —-“);
      return;

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

      Reply
  23. Hi Sarah, hi Rui,

    I replicated this in vscode using platformio but came up to the issue where it waits for the NTP server to synch up and fails due to not being able to connect.

    Reply
  24. Connecting to AP……………
    WiFi connected.
    IP address:
    10.223.98.254

    Connecting to SMTP server…

    C: ESP Mail Client v2.5.2
    C: Wait for NTP server time synching
    Error, NTP server time synching timed out
    E: NTP server time synching timed out
    C: Connect to SMTP server
    C: Host > smtp.gmail.com
    C: Port > 465
    Error, unable to connect to server
    E: unable to connect to server

    could it be that my could is just not connecting.
    thanks,
    Tenzin

    Reply
  25. If you want to use this code to send multiple email messages, maybe providing a regular update to a server or mobile phone, then you need to add the following line at the end of the callback routine to free up allocated memory after each message is sent.

    smtp.sendingResult.clear();

    Reply
  26. Hello Sara and Rui,

    I have seen a few examples of code where the last line of the – void smtpCallback(SMTP_Status status){ – routine includes smtp.sendingResult.clear(); with the explanation that the sending results needs to be cleared or else the memory usage will grow. Do you agree?

    Regards,

    Roger

    Reply
  27. What is the difference between ver. 2.7.2 and 2.7.9? I’m asking because newer than 2.7.2 version doesn’t work properly. A have message “unable to connect to server”(2.7.2 with the same sketch compiled, works fine). A changed ESP core to 3.1.1, 3.10, 3.0.2 and nothing. I’ve noticed that ver. 2.7.3 and newer uses more RAM. Why?

    Reply
  28. Hello, can anyone help me with the following error:
    (I did install the latest esp2866 library 3.1.0)

    In file included from c:\Users\askob\Documents\Arduino\libraries\ESP-Mail-Client-master\src/wcs/custom/Custom_TCP_Client.h:35:0,
    from c:\Users\askob\Documents\Arduino\libraries\ESP-Mail-Client-master\src/wcs/ESP_TCP_Clients.h:53,
    from c:\Users\askob\Documents\Arduino\libraries\ESP-Mail-Client-master\src/ESP_Mail_Client.h:92,
    from C:\Users\askob\AppData\Local\Temp.arduinoIDE-unsaved2023113-17360-2bq38.qm6lej\Send_HTML\Send_HTML.ino:29:
    c:\users\askob\documents\arduino\libraries\esp-mail-client-master\src\wcs\base\tcp_client_base.h:32:10: fatal error: sys/time.h: No such file or directory
    #include <sys/time.h>
    ^~~~~~~~~~~~
    compilation terminated.

    exit status 1

    Compilation error: exit status 1

    Reply
  29. Hi,
    keep getting an ” NTP sync timeout”, can someone give me a hint on where to start debugging?

    serial output:
    ……………………………..
    WiFi connected.
    IP address:
    10.0.0.32

    Connecting to SMTP server…

    C: ESP Mail Client v3.1.3
    C: wait for NTP server time synching

    Error, NTP server time synching timed out

    ! E: NTP server time synching timed out

    I can compile/run the NTP sample code shown in https://RandomNerdTutorials.com/esp32-date-time-ntp-client-server-arduino/ successfully. The ESP mail library code seems to be looking for time information from either pool.ntp.org, or time.nist.gov, both of which work in the ntp sample code. The only issue I have with that code is that lines like

    Serial.println(&timeinfo, “%A, %B %d %Y %H:%M:%S”)

    produce compile errors:
    C:\Users\steff\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266/Print.h:103:16: note: conversion of argument 2 would be ill-formed:
    ntp_sync:57:29: error: invalid conversion from ‘const char‘ to ‘int’ [-fpermissive]
    57 | Serial.println(&timeinfo, “%A, %B %d %Y %H:%M:%S”);
    | ^~~~~~~~~~~~~~~~~~~~~~~
    | |
    | const char

    In file included from C:\Users\steff\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266/Stream.h:27,
    from C:\Users\steff\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266/HardwareSerial.h:32,
    from C:\Users\steff\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266/Arduino.h:303,
    from sketch\ntp_sync.ino.cpp:1:

    Do I need to adjust (which?) preferences do avoid those?

    Thanks in advance for hints/help
    -Steffen

    Reply
  30. Thanks for the excellent code and explanation. My project already has a simple Real Time Clock (RTC) module. Is there a way I can use its time components (hours minutes, seconds, month, day, year) to substitute for the step where the email being sent needs to “Wait for NTP server time synching”?

    Reply

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.