In diesem Beitrag möchte ich dir zeigen wie man eine E-Mail mit dem ESP32 in der Arduino IDE versenden kann.
Für diesen Beitrag verwende ich den recht neuen Lolin S2 mini auf welchem ein ESP32 Chip verbaut ist. Du kannst aber auch (fast) jeden anderen Mikrocontroller mit ESP32 / ESP8266 Chip verwenden, dieser muss lediglich in der Arduino IDE erkannt werden.
Einrichten einer E-Mail
In diesem Beispiel möchte ich von einer Gmail Adresse mithilfe des Lolin S2 mini eine E-Mail versenden. Wie man das App-Passwort für eine Gmail Adresse erstellt wird im Hilfebereich https://support.google.com/accounts/answer/185833?hl=de sehr ausführlich erläutert. Solltest du einen anderen Mailprovider verwenden, so musst du dort in der Hilfe schauen.
Bibliothek zum versenden einer E-Mail
Eine Bibliothek kann viel Arbeit ersparen und man muss ja schließlich das Rad nicht neu erfinden. Des Weiteren kann man davon profitieren, dass dort ggf. schon Fehlerquellen erkannt und umgangen / behandelt werden.
Für diesen Beitrag habe ich die Bibliothek “ESP Mail Client” von Mobizt.
Auf dem GitHub Repository von Mobizt findest du neben der Bibliothek auch einige Beispiele wie du diese verwenden kannst.
In meinem Fall verwende ich als Basis https://github.com/mobizt/ESP-Mail-Client/tree/master/examples/SMTP/Send_Text und passe diese auf meine Bedürfnisse an.
Programm
Wie erwähnt nutze ich das Beispiel “Send_Text” von Mobizt. Dieses findest du entweder auf dem verlinkten GitHub Repository oder aber auch in den Beispielen innerhalb der Arduino IDE.
Aufbau des Programmes
Um eine E-Mail zu versenden, müssen wir:
- eine Verbindung zum Server aufbauen,
- eine Message definieren
- einen oder mehrere Empfänger definieren,
- die Mail absenden,
- das Ergebnis prüfen
Diese genannten Schritte schauen wir uns einmal im Detail am genannten Beispiel an.
einbinden der Bibliotheken
Zunächst müssen wir ein paar Bibliotheken einbinden.
#include <WiFi.h> #include <ESP_Mail_Client.h>
Wenn du einen ESP8266 verwendest, so musst du stattdessen folgende Bibliotheken einbinden:
#include <ESP8266WiFi.h> #include <ESP_Mail_Client.h>
definieren der Zugangsdaten zum lokalen WiFi Netzwerk
Damit der Mikrocontroller auf das lokale Wi-Fi Netzwerk zugreifen kann, benötigt dieser die SSID sowie das Passwort.
#define WIFI_SSID "<ssid>" #define WIFI_PASSWORD "<password>"
definieren der Serverdaten
Für den späteren Aufbau der Verbindung zum Mailprovider benötigen wir
- SMTP_HOST – der Postausgangsserver
- SMTP_PORT – eine Zahl oder Konstante aus der Bibliothek
- 25 oder esp_mail_smtp_port_25
- 465 oder esp_mail_smtp_port_465
- 587 oder esp_mail_smtp_port_25
- AUTHOR_EMAIL – die E-Mail-Adresse des Absenders (wird für die Anmeldung benötigt)
- AUTHOR_PASSWORD – das Passwort für die Anmeldung*
* Hier wird von Gmail das App-Passwort eingetragen.
#define SMTP_HOST "smtp.gmail.com" #define SMTP_PORT esp_mail_smtp_port_587 #define AUTHOR_EMAIL "stefandraeger1980@gmail.com" #define AUTHOR_PASSWORD "<geheim>"
definieren von weiteren Feldern
Für den globalen Zugriff auf die SMTPSession sowie auf den Callback benötigen wir noch zwei zusätzliche Zeilen im Kopfbereich unseres Programmes.
SMTPSession smtp; void smtpCallback(SMTP_Status status);
Funktion “setup”
Die Funktion “setup” wird aufgerufen, wenn der Mikrocontroller gestartet wird, d.h. einmalig.
Zunächst bauen wir, wie bereits aus anderen Beiträgen bekannt, die Wi-Fi Verbindung zum lokalen Netzwerk auf und geben die empfangene IP-Adresse auf der Konsole aus.
Serial.begin(115200); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); while (WiFi.status() != WL_CONNECTED){ Serial.print("."); delay(200); } //Wenn die Verbindung erfolgreich aufgebaut wurde, //dann soll die IP-Adresse auf der seriellen Schnittstelle //ausgegeben werden. Serial.println(""); Serial.println("WiFi connected."); Serial.println("IP address: "); Serial.println(WiFi.localIP()); Serial.println();
erzeugen der SMTPSession
Wenn dieses erfolgt ist, können wir die SMTPSession erzeugen.
//Debug Meldungen anzeigen smtp.debug(1); //Ein Callback definieren welcher nach dem Senden der Mail ausgeführt werden soll. smtp.callback(smtpCallback); //Mail Session ESP_Mail_Session session; //Serverdaten setzen 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 = "smtp.gmail.com";
Nachdem die Server-/ Anmeldedaten eingetragen wurden, bauen wir eine Verbindung zum Server auf.
//Wenn keine Verbindung aufgebaut werden konnte soll die Funktion verlassen werden. if (!smtp.connect(&session)){ return; }
Wenn dieses jedoch fehlschlägt, so wird die Funktion “setup” an dieser Stelle verlassen und der Mikrocontroller macht nichts weiter.
Aufbau der E-Mail / Message
Nachdem die Session aufgebaut wurde und eine Verbindung zum Server erfolgreich hergestellt werden konnte, erzeugen wir die E-Mail bzw. das SMTP_Message Objekt.
//Aufbau der E-Mail SMTP_Message message; //Im Header kann man recht einfach dem Absender Faken message.sender.name = "Mail vom Lolin S2 mini"; //steht bei "gesendet von" message.sender.email = "max.mustermann@draeger-it.blog"; //der Absender (oder eine Fake E-Mail) message.subject = "nur ein Test"; //der Betreff der E-Mail message.addRecipient("Jon Doe", "stefandraeger1980@gmail.com"); //der Empfänger //Aufbau des Contents der E-Mail String textMsg = "Hier steht ein Text welcher versendet werden soll. \r\n Mit einem Zeilenumbruch."; message.text.content = textMsg.c_str(); message.text.charSet = "utf-8"; message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; //Eine eindeutige ID welche die Mail kennzeichnet //zwischen den spitzen Klammern kann ein Wert xyz@domain.com eingetragen werden message.addHeader("Message-ID: <abcde.fghij@gmail.com>");
Absenden der E-Mail
Nun wird noch die Mail versendet und bei einem Fehlerfall eine Fehlermeldung auf der seriellen Schnittstelle ausgegeben.
//Absenden der E-Mail if (!MailClient.sendMail(&smtp, &message)){ //Im Fehlerfall wird der Grund auf der seriellen Schnittstelle ausgegeben. Serial.println("Error sending Email, " + smtp.errorReason()); }
Callback für die Auswertung des Sendens der E-Mail
Hier nun der Callback für das Auswerten des Sendens der E-Mail.
Diese Funktion ist 1:1 aus dem Beispiel übernommen worden.
//Der Callback welcher ausgeführt werden soll wenn das versenden der E-Mail erfolgte. void smtpCallback(SMTP_Status status){ Serial.println(status.info()); 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"); //smtp.sendingResult.clear(); } }
E-Mail im Webclient von Gmail
Nachdem wir eine E-Mail versendet haben, schauen wir uns diese einmal in dem Webclient von Gmail an.
Das fertige Programm zum Versenden von einfachen E-Mails mit Text
// Einbinden der Bibliotheken #include <WiFi.h> #include <ESP_Mail_Client.h> //Zugangsdaten zum lokalen Wi-Fi Netzwerk #define WIFI_SSID "ssid" #define WIFI_PASSWORD "pwd" //SMTP Serverdaten #define SMTP_HOST "smtp.gmail.com" #define SMTP_PORT esp_mail_smtp_port_587 //Logindaten #define AUTHOR_EMAIL "eine_mail_adresse@gmail.com" #define AUTHOR_PASSWORD "ein_geheimes_passwort" SMTPSession smtp; void smtpCallback(SMTP_Status status); void setup(){ //begin der seriellen Kommunikation mit 115200 baud Serial.begin(115200); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); while (WiFi.status() != WL_CONNECTED){ Serial.print("."); delay(200); } //Wenn die Verbindung erfolgreich aufgebaut wurde, //dann soll die IP-Adresse auf der seriellen Schnittstelle //ausgegeben werden. Serial.println(""); Serial.println("WiFi connected."); Serial.println("IP address: "); Serial.println(WiFi.localIP()); Serial.println(); //Debug Meldungen anzeigen smtp.debug(1); //Ein Callback definieren welcher nach dem Senden der Mail ausgeführt werden soll. smtp.callback(smtpCallback); //Mail Session ESP_Mail_Session session; //Serverdaten setzen 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 = "smtp.gmail.com"; //Wenn keine Verbindung aufgebaut werden konnte soll die Funktion verlassen werden. if (!smtp.connect(&session)){ return; } //Aufbau der E-Mail SMTP_Message message; //Im Header kann man recht einfach dem Absender Faken message.sender.name = "Mail vom Lolin S2 mini"; //steht bei "gesendet von" message.sender.email = "max.mustermann@draeger-it.blog"; //der Absender (oder eine Fake E-Mail) message.subject = "nur ein Test"; //der Betreff der E-Mail message.addRecipient("Jon Doe", "stefandraeger1980@gmail.com"); //der Empfänger //Aufbau des Contents der E-Mail String textMsg = "Hier steht ein Text welcher versendet werden soll. \r\n Mit einem Zeilenumbruch."; message.text.content = textMsg.c_str(); message.text.charSet = "utf-8"; message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; //Eine eindeutige ID welche die Mail kennzeichnet //zwischen den spitzen Klammern kann ein Wert xyz@domain.com eingetragen werden message.addHeader("Message-ID: <abcde.fghij@gmail.com>"); //Absenden der E-Mail if (!MailClient.sendMail(&smtp, &message)){ //Im Fehlerfall wird der Grund auf der seriellen Schnittstelle ausgegeben. Serial.println("Error sending Email, " + smtp.errorReason()); } ESP_MAIL_PRINTF("Free Heap: %d\n", MailClient.getFreeHeap()); } void loop(){} //Der Callback welcher ausgeführt werden soll wenn das versenden der E-Mail erfolgte. void smtpCallback(SMTP_Status status){ Serial.println(status.info()); 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"); //smtp.sendingResult.clear(); } }