How to send email and text messages using ESP8266

Send Text and Email from NodeMCU

Earlier we looked at a method of programming ESP8266 to send sensor data directly to Google Sheets without using any third party modules. Now, we will expand that a little bit and learn to send an email as well as a text message (SMS) using ESP8266. In this demo, we will configure our ESP8266 to send an email and a text message when the value of a variable (which could be a sensor output, or any other physical quantity) goes beyond a threshold limit.

This is not entirely a new topic as there are similar tutorials available online to show how to do this. This article particularly focusses on just using the ESP8266 and Google environment to send email or a text message.

Send Text and Email from NodeMCU

Send Text and Email from NodeMCU

Hardware requirement:

To understand the concept, all we need is an ESP8266 module and a power supply for it, usually a USB cable. I am using a NodeMCU board for convenience. We do not need any sensors or other things. For illustration of the method, we will just generate a random number between certain intervals, and if the number goes beyond what we have set for threshold limit, we would like to receive an email and/or a text message.

Prepare a Google Sheets:

Just like in pushing data to ESP8266 to Google Sheets, we will create a new Google Sheet in a Google Drive. So, let’s do the following:
1) Open up your Google Drive in a web browser and create a Google Sheets. You can call this file whatever you like. I called it ‘SendEmailAndText_ESP8266’.
2) From the Google Sheets that you just created, go to Tools > Script editor…

GAS > Tools > Script Editor

GAS > Tools > Script Editor

3) Give a name to the Script editor main file in the toolbar (whatever you like).
4) Paste the following code to the Code.gs file (assuming you haven’t change the default file name). Again, this filename doesn’t matter either.

Google Scripts Code:
// Created by: Akshaya Niraula
// Date: 2016 December 15th.
 
// Steps are valid as of 2016 December 15th.
// 0) From Google spreadsheet, Tools > Script Editor...
// 1) Write your code
// 2) Save and give a meaningful name
// 3) Run and make sure "doGet" is selected
//    You can set a method from Run menu
// 4) When you run for the first time, it will ask 
//    for the permission. You must allow it.
//    Make sure everything is working as it should.
// 5) From Publish menu > Deploy as Web App...
//    Select a new version every time it's published
//    Type comments next to the version
//    Execute as: "Me (your email address)"
//    MUST: Select "Anyone, even anonymous" on "Who has access to this script"
//    For the first time it will give you some prompt, accept it.
//    You will need the given information (url) later. This doesn't change, ever!
 
 
var number = "8001239999"; // your phone number 
var domain = "tmomail.net"; // You may find your domain for you carrier at: http://www.emailtextmessages.com/
var toEmail = "YourOrFriendsEmail@gmail.com";
 
function doGet(e){
  Logger.log("--- doGet ---");
 
  // for debugging
  if (e == null){e={}; e.parameters = {value:"-1"};}
 
  try{
    // get the values from parameters to local var
    var value = e.parameters.value;
    var phoneEmail = number + "@" + domain;
 
    // Send Text Message (SMS)
    send_Email(phoneEmail, "NodeMCU here, your sensor went beyond your threshold. Sensor reported: " + value + " on:" + new Date()); 
 
    // Send Email
    var message = "<b>Dear User,</b>
 
Your equipment has reached it's threshold value. It just reported a value of " + value + ". Please take a necessary action.
";
    message += "As a valued customer, we have sent you a text message also. 
 
";
    message += "To learn more about this email, please click on the link below: 
";
    message += "<a href="http://www.embedded-lab.com/" target="new">www.Embedded-Lab.com</a>
 
 
";
    message += "Sincerely,
<b>NodeMCU ESP8266</b>";
 
    send_Email(toEmail, message)
 
    return ContentService.createTextOutput("Things went successfully.");
  }  
   catch(error) {
    Logger.log(JSON.stringify(error));
    return ContentService.createTextOutput("oops...." + error.message 
                                            + "\n" + new Date() 
                                            + "\nnumber: " + number +
                                            + "\ndomain: " + domain);
  }
 
}
 
function send_Email(address, message){
 
  MailApp.sendEmail({
          "to": address,
     "subject": "Threshold reached - ESP8266",
    "htmlBody": message      
   });
 
  Logger.log("send_textMessage: " + "Email sent to: " + address);
}
Download Google App Script Code
Test the progress:

As shown in the image below, select doGet and click on bug icon to debug your code. If you followed the steps properly, you should have received a text message and an email from you gmail account.

Please note Google will need your permissions to send email on your behalf so when Google asks for the permission, you must provide it.

GAS > Debug > DoGet

GAS > Debug > DoGet

If you didn’t receive a text message and/or an email, please double check your steps. If you did receive then let’s publish our work so that we can get a URL which we can use in NodeMCU. To publish, click on Publish > Deploy as web app…

GAS > Publish menu

GAS > Publish menu

Above action will show the following window. Make sure to select all the three steps as shown in the image below.

GAS > Deploy as Web App

GAS > Deploy as Web App

When you click on Update or Publish, you will see a box as shown below. From this box, copy the given address. I usually save this address back into Google Script for future use. We will need this address in NodeMCU/ESP8266 code.

Note: we will call the text between /s/ and /exec as GScriptID. This information is required in NodeMCU code.

GAS > Deploy as web app > Result

GAS > Deploy as web app > Result

Grab the URL from above box and append the “?value=-1” to it, it will look something like this:
https://script.google.com/macros/s/—YourGScriptIDGoesHere—/exec?value=-1. Now paste this URL to your browser’s address and press enter. In a few seconds you should receive an email and a text message.

NodeMCU / ESP8266 Code:

Please make sure to grab the library file that helps us redirect to the URL that we need. This process has been explained in How To Post Data To Google Sheets Using Esp8266.

// BY: Akshaya Niraula
// ON: Jan 4, 2017
// AT: http://www.embedded-lab.com/

#include <ESP8266WiFi.h>
#include “HTTPSRedirect.h”

const char* ssid = “–Your SSID–“;
const char* password = “–Your Password–“;

// The ID below comes from URL
// after publishing Google Script as Web App.
const char *GScriptId = “–Your GScriptId–“;

const char* host = “script.google.com”;
const char* googleRedirHost = “script.googleusercontent.com”;

const int httpsPort =     443;
HTTPSRedirect client(httpsPort);

// Prepare the url (without the varying data)
String url = String(“/macros/s/”) + GScriptId + “/exec?”;

const char* fingerprint = “F0 5C 74 77 3F 6B 25 D7 3B 66 4D 43 2F 7E BC 5B E9 28 86 AD”;

void setup() {
    Serial.begin(115200);
    Serial.println(“Connecting to wifi: “);
    Serial.println(ssid);
    Serial.flush();

    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
            delay(500);
            Serial.print(“.”);
    }
    Serial.println(” IP address: “);
    Serial.println(WiFi.localIP());

    
    Serial.print(String(“Connecting to “));
    Serial.println(host);

    bool flag = false;
    for (int i=0; i<5; i++){
            int retval = client.connect(host, httpsPort);
            if (retval == 1) {
                        flag = true;
                        break;
            }
            else
                    Serial.println(“Connection failed. Retrying…”);
    }

    // Connection Status, 1 = Connected, 0 is not.
    Serial.println(“Connection Status: “ + String(client.connected()));
    Serial.flush();
    
    if (!flag){
            Serial.print(“Could not connect to server: “);
            Serial.println(host);
            Serial.println(“Exiting…”);
            Serial.flush();
            return;
    }

    // Data will still be pushed even certification don’t match.
    if (client.verify(fingerprint, host)) {
            Serial.println(“Certificate match.”);
    } else {
            Serial.println(“Certificate mis-match”);
    }
}

// This is the main method where data gets pushed to the Google sheet
void sendValueToGoogle(String value){
    if (!client.connected()){
            Serial.println(“Connecting to client again…”);
            client.connect(host, httpsPort);
    }
    String urlFinal = url + “value=” + value;
    client.printRedir(urlFinal, host, googleRedirHost);
}

// Continue pushing data at a given interval
void loop() {

    // Here you will have your main code
    // To demonstrate the concept we are generating a random number
    long randomValue = random(10, 20);

    // Our lower threshold is 12 and upper threshold is 18
    // when given vlaue goes below lower or above upper the threshold
    // we would like to send information to GAS for email and text message
    if (randomValue < 12 || randomValue > 18) {
            Serial.println(“Random value outside the threshold: “ + String(randomValue));
            sendValueToGoogle(String(randomValue));
    }
        
    delay (10000); // wait 10 sec
}

Download Arduino .ino code file

Related Posts

11 comments

  • Hi,
    I followed same exact steps as you said. But i didn’t get mail and sms too..

    • This works great. Go review the PostDataToGoogle tutorial he mentions at start if you had problems with this. Everything works and perfect example .ino in the SendEmailAndText.zip, All working as of October 2017. Been wondering how to do this. Thanks

      • Thanks for confirming that it still works!

      • How to Post multiple data to Google Sheet:
        (Here are bits and pieces of the codes, please stitch them together…)

        //
        // Format data as JSON string
        String formatDataToJson(String tag, String value){
        return String("\"" + tag + "\":\"" + value + "\"");
        }

        //
        // This is the main method where data gets pushed to the Google sheet
        void postData(String dataToPost){
        Serial.println("Data to post: " + dataToPost);

        if (!client.connected()){
        Serial.println("Connecting to client again...");
        client.connect(host, httpsPort);
        }
        String urlFinal = url + "data=" + dataToPost;
        client.printRedir(urlFinal, host, googleRedirHost);
        }

        //
        // Continues to loop forever
        void loop(){

        String dataBuilder = "{";

        // Read analog value, in this case a soil moisture
        int moisture = analogRead(AnalogIn);
        dataBuilder.concat(formatDataToJson(tag + "Moist", String(1023 - moisture)));
        dataBuilder.concat(",");

        // Read Tempearture from BME280
        float temp = bme.readTemperature();
        if(temperatureInF){temp = temp * 9 / 5 + 32;}
        dataBuilder.concat(formatDataToJson(tag + "Temp", String(temp)));
        dataBuilder.concat(",");

        // Read Humidity from BME280
        float humid = bme.readHumidity();
        dataBuilder.concat(formatDataToJson(tag + "Humid", String(humid)));
        dataBuilder.concat(",");

        // Read Pressure from BME280
        float pressure = bme.readPressure()/100.0F;
        dataBuilder.concat(formatDataToJson(tag + "Pressure", String(pressure)));
        dataBuilder.concat(",");

        // Read Light Intensity
        float lux = getTSLData();
        if (lux != -1){
        dataBuilder.concat(formatDataToJson(tag + "Light", String(lux)));
        }

        dataBuilder.concat("}");

        // Post all the data at once
        postData(dataBuilder);

        // Wait for given time
        delay (dataPostDelay);

        }

        NOW on the GAS side..

        // this helps during debuggin
        if (e == null){e={}; e.parameters = {"data":{"tag1":"value1","tag2":"value2","tag3":"value3"}}}

        dataReceived = e.parameters.data;
        // pass this to save_data(dataReceived)

        // Method to save given data to a sheet
        function save_data(dataSet){
        Logger.log("--- save_data ---");

        try {
        var dateTime = new Date();

        // Paste the URL of the spreadsheeet starting from https thru /edit
        // For e.g.: https://docs.google.com/..../edit
        var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/---Your-Google-Sheet-Info-From-Address-Bar---/edit");
        var summarySheet = ss.getSheetByName("Summary");
        var dataLoggerSheet = ss.getSheetByName("DataLogger");

        // Get last edited row from DataLogger sheet
        var row = dataLoggerSheet.getLastRow() + 1;

        // Start Populating the data
        for(var data in dataSet){
        dataLoggerSheet.getRange("A" + row).setValue(row -1); // ID
        dataLoggerSheet.getRange("B" + row).setValue(dateTime); // dateTime
        dataLoggerSheet.getRange("C" + row).setValue(dataSet[data]); // tag
        dataLoggerSheet.getRange("D" + row).setValue(dataSet[data]); // value

        row += 1;
        };

        // Update summary sheet
        summarySheet.getRange("B1").setValue(dateTime); // Last modified date
        }

        catch(error) {
        Logger.log(JSON.stringify(error));
        }

        Logger.log("--- save_data end---");
        }

  • Result:

    �Connecting to wifi:
    MyPhone
    ..
    connected, IP address: 172.20.10.3
    Connecting to script.google.com
    Connection Status: 1
    End setup()
    End sendValueToGoogle()
    eMail sent – SYSTEM Start UP [Not received any email]
    Zone 1 : 1
    Zone 2 : 2
    Zone 3 : 3
    Zone 4 : 4
    Zone 5 : 5
    Zone 6 : 6
    Zone 7 : 7
    Zone 8 : 8
    Zone 9 : 9
    heap: 18640
    Firebase Connecting…
    Firebase Connected

    Exception (29):
    epc1=0x4000e1b2 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000004 depc=0x00000000

    ctx: cont
    sp: 3fff1180 end: 3fff1790 offset: 01a0

    >>>stack>>>
    3fff1320: 3fff067c 000013e3 000013e3 4022572f
    3fff1330: 00000208 3fff4d14 3fffb014 ………….
    .
    .
    .
    3fff1770: feefeffe feefeffe 3fff0760 40100718
    <<<stack<<<

    ets Jan 8 2013,rst cause:2, boot mode:(3,7)

    load 0x4010f000, len 1384, room 16
    tail 8
    chksum 0x2d
    csum 0x2d
    v6000001c
    ~ld
    �Connecting to wifi:
    .
    .
    .

    • I am sorry Prasit, I am not sure I follow you. Could you please summarize your difficulty? Thanks.

      • use your code together with command to update data to firebase:

        Firebase.setInt(“database_field_name”,Integer_value);

        will cause
        Exception (29):
        epc1=0x4000e1b2 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000004 depc=0x00000000

        and rebooting.

        And good news. I can use your code to send text value to email, so the message of email could changed from event to event. Only that the text must be conform to URL rule (no space, for example).

        Thank you for your code.
        Prasit

  • ?? the code and result that I sent was mixed and loss text??
    This is the code:
    #include “ESP8266WiFi.h”
    #include “FirebaseArduino.h”
    #include “HTTPSRedirect.h”

    // Config Firebase
    #define FIREBASE_HOST “xxxxxxxxxx.firebaseio.com”
    #define FIREBASE_AUTH “LxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzVP”

    // Config connect WiFi
    #define WIFI_SSID “xxxxxxx”
    #define WIFI_PASSWORD “xxxxxxxxxxxxxx”

    // The ID below comes from URL
    // after publishing Google Script as Web App.
    const char *GScriptId = “AKxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0”;

    const char* host = “script.google.com”;
    const char* googleRedirHost = “script.googleusercontent.com”;

    const int httpsPort = 443;
    HTTPSRedirect client(httpsPort);

    // Prepare the url (without the varying data)
    String url = String(“/macros/s/”) + GScriptId + “/exec?”;

    #define D0 16 // GPIO16 Belong to RTC for wake after deep sleep
    #define D1 5 // GPIO 5 I2C Bus SCL (clock) Connect to Zone 1
    #define D2 4 // GPIO 4 I2C Bus SDA (data) Connect to Zone 2
    #define D3 0 // GPIO 0 Connect to Zone 3
    #define D4 2 // GPIO 2 Same as “LED_BUILTIN”, but inverted logic Connect to Zone 4
    #define D5 14 // GPIO 14 SPI Bus SCK (clock) Connect to Zone 5
    #define D6 12 // GPIO 2 SPI Bus MISO Connect to Zone 6
    #define D7 13 // GPIO 13 SPI Bus MOSI Connect to Zone 7
    #define D8 15 // GPIO 15 SPI Bus SS (CS) Connect to Alarm Trig/Bell Input
    #define D9 3 // GPIO 3 RX0 (Serial console) Connect to Electricity of the house

    int ZD1=1;
    int ZD2=2;
    int ZD3=3;
    int ZD4=4;
    int ZD5=5;
    int ZD6=6;
    int ZD7=7;
    int ZD8=8;
    int ZD9=9;

    int Require_email_Alarm_case =1;
    int Require_email_Power_Loss_case =1;
    int System_Start_up =1;

    void setup() {
    Serial.begin(115200);

    pinMode(D1, INPUT);
    pinMode(D2, INPUT);
    pinMode(D3, INPUT);
    pinMode(D4, INPUT);
    pinMode(D5, INPUT);
    pinMode(D6, INPUT);
    pinMode(D7, INPUT);
    pinMode(D8, INPUT);
    pinMode(D9, INPUT);

    // connect to wifi.
    Serial.println(“Connecting to wifi: “);
    Serial.println(WIFI_SSID);

    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
    while (WiFi.status() != WL_CONNECTED) {
    Serial.print(“.”);
    delay(500);
    }
    Serial.println();
    Serial.print(“connected, IP address: “);
    Serial.println(WiFi.localIP());

    Serial.print(String(“Connecting to “));
    Serial.println(host);

    bool flag = false;
    for (int i=0; i<5; i++){
    int retval = client.connect(host, httpsPort);
    if (retval == 1) {
    flag = true;
    break;
    }
    else
    Serial.println("Connection failed. Retrying…");
    }

    // Connection Status, 1 = Connected, 0 is not.
    Serial.println("Connection Status: " + String(client.connected()));
    Serial.flush();

    if (!flag){
    Serial.print("Could not connect to server: ");
    Serial.println(host);
    Serial.println("Exiting…");
    Serial.flush();
    return;
    }

    Serial.println("End setup()");
    }

    // This is the main method where data gets pushed to the Google sheet
    void sendValueToGoogle(String value){
    if (!client.connected()){
    // Serial.println("Connecting to client again…");
    client.connect(host, httpsPort);
    }
    String urlFinal = url + "value=" + value;
    client.printRedir(urlFinal, host, googleRedirHost);

    Serial.println("End sendValueToGoogle()");
    }

    void loop() {

    // ***** SMS or email to notify system startup
    if (System_Start_up=1) {
    sendValueToGoogle("SYSTEM Start UP");
    System_Start_up=0;
    Serial.println("eMail sent – SYSTEM Start UP");
    }

    /*
    ZD1 = digitalRead(D1);
    ZD2 = digitalRead(D2);
    ZD3 = digitalRead(D3);
    ZD4 = digitalRead(D4);
    ZD5 = digitalRead(D5);
    ZD6 = digitalRead(D6);
    ZD6 = digitalRead(D6);
    ZD7 = digitalRead(D7);
    ZD8 = digitalRead(D8);
    ZD9 = digitalRead(D9);
    ZD10 = digitalRead(D10);
    */

    Serial.print("Zone 1 : ");
    Serial.println(ZD1);
    Serial.print("Zone 2 : ");
    Serial.println(ZD2);
    Serial.print("Zone 3 : ");
    Serial.println(ZD3);
    Serial.print("Zone 4 : ");
    Serial.println(ZD4);
    Serial.print("Zone 5 : ");
    Serial.println(ZD5);
    Serial.print("Zone 6 : ");
    Serial.println(ZD6);
    Serial.print("Zone 7 : ");
    Serial.println(ZD7);
    Serial.print("Zone 8 : ");
    Serial.println(ZD8);
    Serial.print("Zone 9 : ");
    Serial.println(ZD9);

    Serial.print("heap: ");
    Serial.println(ESP.getFreeHeap());

    Serial.println("Firebase Connecting…");
    Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
    Serial.println("Firebase Connected");

    if (Firebase.failed()) {
    Serial.println(Firebase.error());
    }
    Firebase.setInt("/Z1",ZD1);
    Firebase.setInt("/Z2",ZD2);
    Firebase.setInt("/Z3",ZD3);
    Firebase.setInt("/Z4",ZD4);
    Firebase.setInt("/Z5",ZD5);
    Firebase.setInt("/Z6",ZD6);
    Firebase.setInt("/Z7",ZD7);
    Firebase.setInt("/Z8",ZD8);
    Firebase.setInt("/Z9",ZD9);

    if (Firebase.failed()) {
    Serial.println(Firebase.error());
    }

    Serial.println("End one loop");
    delay(5000); // wait 5 sec
    }

  • #include “ESP8266WiFi.h”
    #include “FirebaseArduino.h”
    #include “HTTPSRedirect.h”

    it keeps rebooting….

  • #include
    #include
    #include “HTTPSRedirect.h”

  • Hi ANir,

    Very good instruction and sample.

    I use your code and instruction with a home project – to show the status of each Burglar Alarm to FireBase Database. And want to send email when the alarm bell set off, with zone number that trig the alarm. Also if the system run on battery in case the power was loss.

    The upload of each zone to firebase database is working.

    The your email code is working.

    But when integrate emailing code into the firebase database code, some conflicts happened. update to firebase database not functioned. And email also not function. Any suggestions, please?

    Thanks, Prasit
    ———————————————————————–

    Here the code:
    #include
    #include
    #include “HTTPSRedirect.h”

    // Config Firebase
    #define FIREBASE_HOST “xxxxxxxxxx.firebaseio.com”
    #define FIREBASE_AUTH “LxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzVP”

    // Config connect WiFi
    #define WIFI_SSID “xxxxxxx”
    #define WIFI_PASSWORD “xxxxxxxxxxxxxx”

    // The ID below comes from URL
    // after publishing Google Script as Web App.
    const char *GScriptId = “AKxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0”;

    const char* host = “script.google.com”;
    const char* googleRedirHost = “script.googleusercontent.com”;

    const int httpsPort = 443;
    HTTPSRedirect client(httpsPort);

    // Prepare the url (without the varying data)
    String url = String(“/macros/s/”) + GScriptId + “/exec?”;

    #define D0 16 // GPIO16 Belong to RTC for wake after deep sleep
    #define D1 5 // GPIO 5 I2C Bus SCL (clock) Connect to Zone 1
    #define D2 4 // GPIO 4 I2C Bus SDA (data) Connect to Zone 2
    #define D3 0 // GPIO 0 Connect to Zone 3
    #define D4 2 // GPIO 2 Same as “LED_BUILTIN”, but inverted logic Connect to Zone 4
    #define D5 14 // GPIO 14 SPI Bus SCK (clock) Connect to Zone 5
    #define D6 12 // GPIO 2 SPI Bus MISO Connect to Zone 6
    #define D7 13 // GPIO 13 SPI Bus MOSI Connect to Zone 7
    #define D8 15 // GPIO 15 SPI Bus SS (CS) Connect to Alarm Trig/Bell Input
    #define D9 3 // GPIO 3 RX0 (Serial console) Connect to Electricity of the house

    int ZD1=1;
    int ZD2=2;
    int ZD3=3;
    int ZD4=4;
    int ZD5=5;
    int ZD6=6;
    int ZD7=7;
    int ZD8=8;
    int ZD9=9;

    int Require_email_Alarm_case =1;
    int Require_email_Power_Loss_case =1;
    int System_Start_up =1;

    void setup() {
    Serial.begin(115200);

    pinMode(D1, INPUT);
    pinMode(D2, INPUT);
    pinMode(D3, INPUT);
    pinMode(D4, INPUT);
    pinMode(D5, INPUT);
    pinMode(D6, INPUT);
    pinMode(D7, INPUT);
    pinMode(D8, INPUT);
    pinMode(D9, INPUT);

    // connect to wifi.
    Serial.println(“Connecting to wifi: “);
    Serial.println(WIFI_SSID);

    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
    while (WiFi.status() != WL_CONNECTED) {
    Serial.print(“.”);
    delay(500);
    }
    Serial.println();
    Serial.print(“connected, IP address: “);
    Serial.println(WiFi.localIP());

    Serial.print(String(“Connecting to “));
    Serial.println(host);

    bool flag = false;
    for (int i=0; i>>stack>>>
    3fff1320: 3fff067c 000013e3 000013e3 4022572f
    3fff1330: 00000208 3fff4d14 3fffb014 ………….

Leave a Reply

Your email address will not be published. Required fields are marked *