Senden einer E-Mail mit dem ESP32 via Arduino IDE

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.

Bibliothek "ESP Mail Client" von Mobizt im Bibliothekverwalter der Arduino IDE
Bibliothek „ESP Mail Client“ von Mobizt im Bibliothekverwalter der Arduino IDE

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.

Beispiel "Send_Text" von ESP Mail Client Bibliothek
Beispiel „Send_Text“ von ESP Mail Client Bibliothek

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();
  }
}

Kommentar hinterlassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.