SMTP For Your Embedded Devices

mailboxes-yannik-mika-467222-unsplash
Share on facebook
Share on reddit
Share on twitter
Share on linkedin
Share on email
Share on print

In this article, we give a brief overview of what SMTP is, the settings necessary to get it working, and how it can be used in the embedded world. We will also look at how NetBurner’s products can make this often prickly process a breeze by going through a specific example that will send an email through Gmail’s servers.

In the world of electronics, protocols are the rules that let disparate devices, servers, and services talk to each other. When it comes to transmitting email messages one protocol stands above the rest, and that is the Simple Mail Transfer Protocol (SMTP). Unlike mail retrieval protocols, such as IMAP and POP3, SMTP is used exclusively for transmitting (sending) email to mail servers.

Within embedded systems, SMTP is used widely for delivering system notifications, alerts, and reporting. For example, perhaps you have a few sensors that you want to keep an eye on? With SMTP you can set up your device to send out an email whenever a critical value is reached. Maybe you want to compile usage reports for your device in the field? You can program your device to collect your data and send it out at regular intervals. The list of possible SMTP applications goes on.

SMTP started in the early 1980’s and was purely ASCII text-based. Over the years, it has been extended by other protocols to handle different data formats (see Multipurpose Internet Mail Extensions (MIME)) and data security (see the SMTP Service Extension of Secure SMTP over Transport Layer Security), among others. It has also continued to evolve itself over the years. RFC 5321 has, as of this writing, the most up to date revision of the protocol.

The Basics

Email transmission occurs over a TCP connection between an SMTP client and an SMTP server. Historically, three ports have typically been used for SMTP connections: 25, 465, and 587. Today, the recommended port is 587 with the use of Transport Layer Security (TLS). Port 465 was never officially designated as an SMTP port, though it was commonly used back in the day, and is still used presently in some legacy systems.

Secure connections can happen in one of two ways. The first is for the negotiation to take place right off the bat. The second is for a server to accept an unsecured connection and then upgrade it to a secure one with the use of the STARTTLS command. This is also known as “Opportunistic TLS”. Both methods are supported by the NetBurner system libraries.

Completely unsecure connections are fairly rare these days, as they should be. These would take place over port 25, though connections over this port can also be upgraded using STARTTLS, as explained above. We haven’t seen any services that offer completely unsecure connections lately, and even if we did we wouldn’t recommend using them. More to the point, if you’re hoping to use any of the major email providers, such as Gmail, Office 365, or Yahoo, you will need to use the secure ports.

The big fish in the email pond also typically require some additional settings in order to play nicely with external devices and applications trying to use their services. As such, there are a few details that we need to cover in order to get your SMTP ship sailing as smoothly as possible.

For Gmail, Yahoo, and Office 365, you will need to enable the “less secure apps access”. This option is found in the settings area for both services in your user account. The links to do this can be found below (you will need to be logged into your account to actually see them):

If you happen to have two-factor authentication enabled for your account, you will also need to generate an application password for these services. This will be the password that you use to authenticate your account when trying to send email from the NetBurner device. The steps for creating this password can be found here:

NetBurner Examples

You can find several SMTP example applications in your NetBurner 3.0 install directory at <NetBurner install>/examples/SSL/. The examples we currently provide are as follows:

  • SslSendMail – Demonstrates how to send mail over with the SMTP protocol.
  • SslSendMailAttach – Shows how to send an email with a plain text attachment using the SMTP protocol.
  • SslSendMailAttachEffs – Shows how to send an email with an attachment from the device’s file system using the SMTP protocol.

We will cover the interface and usage of the SslSendMail example, and then point out the areas within the application’s code that do the interesting bits.

After building and loading the application to your device (please see our documentation on the steps needed to do this), open a browser and navigate to your device’s web page by typing its IP address into the URL bar, as shown in the image below:

SMTP Netburner
SMTP setup for NetBurner devices

You will notice that for this demonstration, we are going to use Gmail, with the following settings (other services will require their own special blend):

  • Mail Username: My personal Gmail email address
  • Mail Password: Because I have two-factor authentication turned on, I used the application password generated by Google, which can be done here.
  • SMTP Server: smtp.gmail.com
  • Use STARTTLS: Checked (connection will start as unsecure, and then get upgraded)
  • SMTP Port: 587
  • From Email Address: Also my personal Gmail email address
  • To Address: My work email address

After these fields were filled out, along with the Subject and Message Body, I hit the “Send Mail” button, and got the warm fuzzy feeling of seeing a success message (I also verified that the email was sent by looking in my inbox):

SMTP confirmation notice
NetBurner’s SMTP configuration test

If we crack this example open and see what’s inside, we’ll find two source files, main.cpp and webfuncs.cpp. The first file is pretty typical for all NetBurner examples and simply shows how to get your device up and running. We cover this extensively elsewhere, so we’re going to skip over it this time around.

The second file contains the more interesting code that handles the form POST and sends the mail request. The code that we are the most interested in is found at the end of the file:

 
/**
* @brief A POST callback for the send mail post request. This callback is called for each field
* of a post form.
*
* @param sock HTTP socket.
* @param event The kind of post event that is currently being handled with this callback.
* @param pName The name of the post element that is currently being handled.
* @param pValue The value of the post element that is currently being handled.
*/
void HandleSendMailPost(int sock, PostEvents event, const char *pName, const char *pValue)
{
   // If the event is the start of the post, clear out all of our variables
   if (event == eStartingPost)
   {
       var_user[0] = 0;
       var_pass[0] = 0;
       var_svrip[0] = 0;
       var_svrport[0] = 0;
       var_from[0] = 0;
       var_to[0] = 0;
       var_sub[0] = 0;
       var_body[0] = 0;
       STARTTLS[0] = 0;
       iprintf("Initiating extraction of post data\r\n");
   }
   // If we have received a name/value pair, figure out which one it is and store it
   // accordingly.
   else if (event == eVariable)
   {
       if (strcmp(pName, "user") == 0) { snprintf(var_user, 80, pValue); }
       else if (strcmp(pName, "pass") == 0) { snprintf(var_pass, 80, pValue); }
       else if (strcmp(pName, "svrip") == 0) { snprintf(var_svrip, 80, pValue); }
       else if (strcmp(pName, "svrport") == 0) { snprintf(var_svrport, 6, pValue); }
       else if (strcmp(pName, "STARTTLS") == 0) { snprintf(STARTTLS, 5, pValue); }
       else if (strcmp(pName, "from") == 0) { snprintf(var_from, 80, pValue); }
       else if (strcmp(pName, "to") == 0) { snprintf(var_to, 80, pValue); }
       else if (strcmp(pName, "sub") == 0) { snprintf(var_sub, 80, pValue); }
       else if (strcmp(pName, "body") == 0) { snprintf(var_body, 80, pValue); }
       else { iprintf("Unknown field of \"%s\" with value \"%s\"", pName, pValue); }
   }
   // If we are at the end of the post, we should have everything we need to send the email,
   // so let’s give it a shot.
   else if (event == eEndOfPost)
   {
       iprintf("End of post data extraction\r\n");
       IPADDR SMTP_server;
       DNSResult = GetHostByName(var_svrip, &SMTP_server, IPADDR::NullIP(), TICKS_PER_SECOND * 20);
       if (DNSResult == DNS_OK)
       {
           int svrPort = strtol(var_svrport, NULL, 0);
           if (svrPort == 0) { svrPort = -1; }
           iprintf("Connecting to server: %s (%I) on port %ld\n", var_svrip, SMTP_server, svrPort);
           if (var_pass[0] == '\0')
           {
               iprintf("Error: no password was entered\r\n");
           }
           else
           {
               // This actually sends the message
               SendmailResult = SSL_SendMail(SMTP_server,
                   var_user,
                   var_pass,
                   var_from,
                   var_to,
                   var_sub,
                   var_body,
                   (BOOL)STARTTLS[0],
                   svrPort,
                   var_svrip);
           }
       }
       else
       {
           iprintf("Error - DNS failed for %s\r\n", var_svrip);
       }

       OSTimeDly(TICKS_PER_SECOND * 2);

       RedirectResponse(sock, "sent.html");
   }
}

HtmlPostVariableListCallback gHandleSendMailPost("sendmail.html", HandleSendMailPost);

Above, we have two significant things going on. At the very bottom on the last line, we declare a global variable, gHandleSendMailPost, that will handle POST requests coming from sendmail.html, and associate it with our callback function, HandleSendMailPost(). Above this, we define the callback function itself. This function will get called several times for each POST request:

  1. At the start of each POST, with an event value of eStartingPost
  2. For each name/value pair of the POST, with an event value of eVariable
  3. At the end of the POST, with an event value of eEndOfPost

You can see how each event is handled within the function. When the eEndOfPost event occurs, we put all of our POST field values together and initiate the email request with a call to SSL_SendMail(). A return value of 0 indicates a failure, while a return of 1 indicates success.

With that, we’re all set! The most confusing aspect of getting SMTP going, from our experience, is making sure that we have the correct settings for the specific email service we want to use. Once that is squared away, using SMTP itself with your NetBurner device is pretty straightforward. We’d love to hear how you are using SMTP with your own projects. Feel free to let us know in the comments below!

Share this post

Share on facebook
Share on twitter
Share on linkedin
Share on reddit
Share on email

Subscribe to our Newsletter

Get monthly updates from our Learn Blog with the latest in IoT and Embedded technology news, trends, tutorial and best practices. Or just opt in for product change notifications.

Leave a Reply

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