ESP8266 Arduino SMTP Server

Note: This is the first in a three-part series. Click here for part 2.

I wanted a way to have a DVR (camera system) to trigger an ESP8266 to toggle a pin (for a chime, etc). This specific model of DVR only allows sending mail and sounding a buzzer for motion detected events. One option would be to put a second ESP8266 inside the DVR and put the IO pin on the buzzer output. A method using one ESP8266 rather than two, would be to have the ESP8266 receive the email. So I set off to make an arduino SMTP server.

There was relatively little existing examples of receiving email on arduino, so I got to work, and a couple hours of guess/test got me this sketch, which mostly works with thunderbird:

*this is a rough draft*

#include <ESP8266WiFi.h>

const char* ssid = "treefiddy";
const char* password = "oxymoronicdis";

// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(25);

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

 // prepare GPIO2
 pinMode(2, OUTPUT);
 digitalWrite(2, 0);

 // Connect to WiFi network
 Serial.println();
 Serial.println();
 Serial.print("Connecting to ");
 Serial.println(ssid);

 WiFi.begin(ssid, password);

 while (WiFi.status() != WL_CONNECTED) {
 delay(500);
 Serial.print(".");
 }
 Serial.println("");
 Serial.println("WiFi connected");

 // Start the server
 server.begin();
 Serial.println("Server started");

 // Print the IP address
 Serial.println(WiFi.localIP());
}

void loop() {
 // Check if a client has connected
 WiFiClient client = server.available();
 if (!client) {
 return;
 }

 // Wait until the client sends some data
 Serial.println("new client");
 client.print("220 framistats.local ESMTP Eximrn");
 client.flush();
 while(!client.available()){
 delay(1);
 }
 Serial.println("available");
 String req = client.readStringUntil('n');
 Serial.println(req);
 // Match the request
 int val;
 if ((req.indexOf("HELO") != -1) || (req.indexOf("EHLO") != -1)) {
 client.println("250 Hello " + req.substring(5));
 // client.println("");
 Serial.println("250 Hello " + req.substring(5));
 /* client.println("SIZE 10000000");
 client.println("PIPELINING");
 client.println("HELP");*/
 client.flush();
 delay(1);
 } else {
 Serial.println("invalid request1");
 client.stop();
 return;
 }
 while(!client.available()){
 delay(1);
 }
 req = client.readStringUntil('n');
 Serial.println(req.length());
 if (req == "") {
 Serial.println("blank");
 req = client.readStringUntil('n');
 }
 Serial.println(req);
 if (req.indexOf("FROM") != -1) {
 client.println("250 Ok");
 client.flush();
 delay(1);
 } else {
 Serial.println("invalid request2");
 client.stop();
 return;
 }
 while(!client.available()){
 delay(1);
 }
 req = client.readStringUntil('n');
 while (client.available() >0) client.read();
 Serial.println(req);
 if (req.indexOf("RCPT") != -1) {
 client.println("250 Accepted");
 client.flush();
 delay(1);
 } else {
 Serial.println("invalid request");
 client.stop();
 return;
 }
 while(!client.available()){
 delay(1);
 }
 req = client.readStringUntil('n');
 while (client.available() >0) client.read();
 Serial.println(req);
 if (req.indexOf("DATA") != -1) {
 client.println("354 Enter message, ending with ""."" on a line by itself");
 client.flush();
 delay(1);
 } else {
 Serial.println("invalid request");
 client.stop();
 return;
 }
 while(!client.available()){
 delay(1);
 }
 while (req != ".r") {
 req = client.readStringUntil('n');
 if (req.indexOf("abc") != -1) {
 Serial.println("XXXXXXXXXXXX");
 }
 Serial.println(req);
 }
 client.println("250 OK");
 client.flush();
 delay(500);
 while (client.available() >0) client.read();
 Serial.println(req);
 if (req.indexOf("QUIT") != -1) {
 client.println("221 framistats.local closing connection");
 client.flush();
 delay(1);
 } else {
 Serial.println("invalid request");
 client.stop();
 return;
 }
 // Set GPIO2 according to the request
 digitalWrite(2, val);

 client.flush();

 // Prepare the response
 // String s = "EHLO mail.framistats.localr";
 // Send the response to the client
 Serial.println("Client disonnected");

 // The client will actually be disconnected
 // when the function returns and 'client' object is detroyed
}

The output in a terminal:


new client
available
EHLO [172.21.42.4]

250 Hello [172.21.42.4]

33
MAIL FROM:<[email]@framistats.com>

RCPT TO:<[email]@gmail.com>

DATA

Message-ID: <557211B6.6050107@framistats.com>

Date: Fri, 05 Jun 2015 17:16:38 -0400

From: Derek Yerger <[email]@framistats.com>

User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.7.0

MIME-Version: 1.0

To: [email]@gmail.com

Subject: test

Content-Type: text/plain; charset=utf-8; format=flowed

Content-Transfer-Encoding: 7bit



testing 123...

.

.

invalid request

I think this is really a hack, and the code is obviously littered with debugging stuff and is severely lacking comments. It didn’t work with the DVR, but with the lines starting with “SIZE 10000000” uncommented, it gets as far as EHLO. The DVR programming itself is atrocious, and any handshake failure results in a hardware lock.

For a future trial of this method, a packet sniffer and normal SMTP server will be essential. It’s been ages since I worked with SMTP, really.

Leave a Comment

Your email address will not be published.