sending e-mails using esp8266 and arduino IDE

Hello,

I am currently working on a project with an ESP-8266 module. an e-mail should be sent by pressing a button. I already oriented myself on this source code under the following link

http://playground.arduino.cc/Code/Email

So far everything works. I do not understand some functions. How does this e-mail service work? Is there a connection via Tel-net built or what is it?

Other demands on the project:

In addition to the SMTP2GO server, I also want to send e-mails via other SMTP servers. What options would I have in this case? And what could a solution look like? I have already tried it with the server of gmail but I didn't have any success so far.

Also:

As soon as the button is pressed the ESP8266 works and he is busy with the programm. But I'd like to do other things with the ESP8266 while the email is being sent. What could I do in such a case?

It connects to port 25 (the smtp port) on the server and implements the smtp protocol. It does not use the telnet protocol but you can simulate the smtp protocol using a telnet client; see e.g. telnet exchange server.

Unfortunately, due to abuse by spammers, smtp servers are often locked down pretty tightly. Either locked down by source IP of sender, requiring a login, and often SSL on top of that.

so my esp8266 needs about 22 seconds to send the e-mail. Using the "self-made" debugger i made out the critical points in the code.
-Sending EHLO
-Sending from
-Sending to
-Sending E-Mail

during this time i want to do other stuff with the esp8266. Is it possible to morph the code from a while-loop into an if(handshake)-command? Or is it possible to solve this problem in a different way? does anyone have a different approach for this problem?

byte thisByte;                                     // Variable
int loopCount = 0;                                  // Variable

while(!client.available()) {                               
 delay(1);
 loopCount++;

 // if nothing received for 10 seconds, timeout
 if(loopCount > 10000) {
   client.stop();
   if(debug)
     {
       Serial.println(F("10 sec \r\nTimeout"));
     }
   return 0;
 }

                         
}


respCode = client.peek();             


while(client.available())
{
 thisByte = client.read(); 
 if(debug)
   {
     Serial.write(thisByte);
   }
}

return 1;
}

Get rid of the delay. Use a millis() based approach.

Demonstration code for several things at the same time
Using millis() for timing. A beginners guide

Hello,

I examined the whole problem a bit more closely and noticed that it was not because of this function. The reason for it was probably more inside of the following function:

Client.println (F ("To: receiver@gmail.com"));

In the steps already named, this line takes between 2 and 6 seconds. I do not understand why. there is actually only one string in this function. Does anyone have suggestions here?

You will have to post your full code for anybody to be able to give a sensible answer.

    /*
      Email client sketch for IDE v1.0.5 and w5100/w5200
      Posted 7 May 2015 by SurferTim
   */
    
   #include <SPI.h>
   #include <Ethernet.h>
    
   // this must be unique
   byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x59, 0x67 };  
   // change network settings to yours
   IPAddress ip( 192, 168, 2, 2 );    
   IPAddress gateway( 192, 168, 2, 1 );
   IPAddress subnet( 255, 255, 255, 0 );
    
   char server[] = "smtpcorp.com";
   int port = 2525;
    
   EthernetClient client;
    
   void setup()
   {
     Serial.begin(115200);
     pinMode(4,OUTPUT);
     digitalWrite(4,HIGH);
     Ethernet.begin(mac, ip, gateway, gateway, subnet);
     delay(2000);
     Serial.println(F("Ready. Press 'e' to send."));
   }
    
   void loop()
   {
     byte inChar;
    
     inChar = Serial.read();
    
     if(inChar == 'e')
     {
         if(sendEmail()) Serial.println(F("Email sent"));
         else Serial.println(F("Email failed"));
     }
   }
    
   byte sendEmail()
   {
     byte thisByte = 0;
     byte respCode;
    
     if(client.connect(server,port) == 1) {
       Serial.println(F("connected"));
     } else {
       Serial.println(F("connection failed"));
       return 0;
     }
    
     if(!eRcv()) return 0;
    
     Serial.println(F("Sending hello"));
   // replace 1.2.3.4 with your Arduino's ip
     client.println("EHLO 1.2.3.4");
     if(!eRcv()) return 0;
    
     Serial.println(F("Sending auth login"));
     client.println("auth login");
     if(!eRcv()) return 0;
    
     Serial.println(F("Sending User"));
   // Change to your base64 encoded user
     client.println("xxxx");
    
     if(!eRcv()) return 0;
    
     Serial.println(F("Sending Password"));
   // change to your base64 encoded password
     client.println("yyyy");
    
     if(!eRcv()) return 0;
    
   // change to your email address (sender)
     Serial.println(F("Sending From"));
     client.println("MAIL From: <me@mydomain.com>");
     if(!eRcv()) return 0;
    
   // change to recipient address
     Serial.println(F("Sending To"));
     client.println("RCPT To: <you@yourdomain.com>");
     if(!eRcv()) return 0;
    
     Serial.println(F("Sending DATA"));
     client.println("DATA");
     if(!eRcv()) return 0;
    
     Serial.println(F("Sending email"));
    
   // change to recipient address
     client.println("To: You <you@yourdomain.com>");
    
   // change to your address
     client.println("From: Me <me@mydomain.com>");
    
     client.println("Subject: Arduino email test\r\n");
    
     client.println("This is from my Arduino!");
    
     client.println(".");
    
     if(!eRcv()) return 0;
    
     Serial.println(F("Sending QUIT"));
     client.println("QUIT");
     if(!eRcv()) return 0;
    
     client.stop();
    
     Serial.println(F("disconnected"));
    
     return 1;
   }
    
   byte eRcv()
   {
     byte respCode;
     byte thisByte;
     int loopCount = 0;
    
     while(!client.available()) {
       delay(1);
       loopCount++;
    
       // if nothing received for 10 seconds, timeout
       if(loopCount > 10000) {
         client.stop();
         Serial.println(F("\r\nTimeout"));
         return 0;
       }
     }
    
     respCode = client.peek();
    
     while(client.available())
     {  
       thisByte = client.read();    
       Serial.write(thisByte);
     }
    
     if(respCode >= '4')
     {
       efail();
       return 0;  
     }
    
     return 1;
   }
    
    
   void efail()
   {
     byte thisByte = 0;
     int loopCount = 0;
    
     client.println(F("QUIT"));
    
     while(!client.available()) {
       delay(1);
       loopCount++;
    
       // if nothing received for 10 seconds, timeout
       if(loopCount > 10000) {
         client.stop();
         Serial.println(F("\r\nTimeout"));
         return;
       }
     }
    
     while(client.available())
     {  
       thisByte = client.read();    
       Serial.write(thisByte);
     }
    
     client.stop();
    
     Serial.println(F("disconnected"));
   }

And now the proof please that the specific line takes 5 or 6 seconds. Your code does not contain any timing.

I suggest that you simulate using telnet as described when you go through the google search results that I provided; if so, there is nothing that you can do about that. It might well be that the other side takes long to respond.

But you should not worry too much. Rewriting the code to make use of a finite state machine to get rid of blocking nature of the current code seems straight forward.

Notes:
1)
the below is fully based on your code; if that code contains flaws, they will also be in the modified code.
2)
I can not test this, only compile. Testing is up to you.

=============

Your email functionaility basically consist of a few steps where you send data and wait for a reply. You can put the steps in a finite state machine.

But before we do this, we will first modify eRcv to be non-blocking. The blocking in your case is caused by the while-loop with the delay and can take up to 10 seconds.

Your eRcv returns 0 (error) or 1 (success). For the new approach we need another value that can indicate that eRcv is waiting for a reply. The readable will be to do this is the use of an enum which is nothing more than a type that can ony contain certain values. Place the below near the top of your code (just after the includes_

// email status based on connection or (received) reply
enum EMAILSTATUS
{
  ES_WAITINGFORREPLY,
  ES_TIMEOUT,
  ES_OK,
  ES_FAIL,
};

I think that you can feel what the names will be used for :wink: eRcv will be called numerous times; while waiting for the first byte of the reply , it will return ES_WAITINGFORREPLY. If no reply is received within 10 seconds, it will return ES_TIMEOUT. And ES_OK and ES_FAIL will be returned depending on the reply.

A static variable waitingInProgress is used to keep track of the 'internal' status of eRcv. A second static variable startTime is used to keep track of the time that the code started waiting for a reply.

The below code should contain sufficient comments to understand how it's working. If not, ask.

/*
  receive reply on email command / data
  Returns:
    email status (ES_WAITINGFORREPLY, ES_TIMEOUT, ES_FAIL or ES_OK)
*/
EMAILSTATUS eRcv()
{
  // flag indicating if waiting is in progress or not
  static bool waitingInProgress = false;
  // start time of the wait
  static unsigned long startTime;

  byte respCode;
  byte thisByte;

  // if we're not waiting, start waiting
  if (waitingInProgress == false)
  {
    // indicate that waiting is in progress
    waitingInProgress = true;
    // set the start time
    startTime = millis();
    // indicate to caller that we're waiting for reply
    return ES_WAITINGFORREPLY;
  }

  // check for timeout
  if (waitingInProgress == true)
  {
    if (millis() - startTime >= 10000)
    {
      // cleanup
      client.stop();
      Serial.println(F("\r\nTimeout"));

      // indicate that we're no longer waiting
      waitingInProgress = false;

      // indicate to caller that we did not receive reply in time
      return ES_TIMEOUT;
    }
  }

  // if nothing received yet
  if (client.available() == 0)
  {
    // indicate to caller that we're stillw aiting for reply
    return ES_WAITINGFORREPLY;
  }

  // we got the reply; indicate that we're no longer waiting
  waitingInProgress = false;

  // get the response code
  respCode = client.peek();

  // read and print the received data
  while (client.available())
  {
    thisByte = client.read();
    Serial.write(thisByte);
  }

  // check the first digit of the response code
  if (respCode >= '4')
  {
    efail();
    return ES_FAIL;
  }

  return ES_OK;
}

Notes:
1)
This is basically a state machine but it looks different from the one that I will present later.
2)
The reading of the client data is flawed in my opionion; what if the client hasn't received all data yet? At the next call of eRcv there will immediately be data but it actually belongs to the previous reply. If you ever encounter problems there, you will have to study rfc5321.

Now, everywhere where you call eRcv and check the result, you will need to modify it. Replace

  if (!eRcv()) return 0;

by

  do
  {
    rv = eRcv();
    switch (rv)
    {
      case ES_WAITINGFORREPLY:
        // keep on waiting
        break;
      case ES_TIMEOUT:
      case ES_FAIL:
        return 0;
        break;
      case ES_OK:
        // nothing to do
        break;
    }
  } while (rv == ES_WAITINGFORREPLY);

You will need to add the variable rv near the beginning of sendMail.

byte sendEmail()
{
  byte thisByte = 0;
  byte respCode;

  // return value for eRcv
  EMAILSTATUS rv;
  
  ...
  ...

You can test the above, it should behave the same as your current code.

If you have any questions, ask.

PS
This code will still be blocking code but the blocking has moved to sendMail where it is easier to work around later.

To implement the state machine, you first define the steps (states). I'm using an enum for that. Place the below after your include statements.

// possible email steps
enum EMAILSTEPS
{
  // connect to mail server
  ST_CONNECT,
  // commands and data
  ST_HELO,
  ST_AUTHLOGIN,
  ST_USER,
  ST_PASSWORD,
  ST_MAILFROM,
  ST_RCPTTO,
  ST_DATA,
  ST_COMPOSE,
  ST_QUIT,
  // disconnect
  ST_STOP,
};

// current email step
EMAILSTEPS emailStep;

And your sendEmail() will look like

byte sendEmail()
{
  byte thisByte = 0;
  byte respCode;

  switch (emailStep)
  {
    case ST_CONNECT:
      break;
    case ST_HELO:
      break;
    case ST_AUTHLOGIN:
      break;
    case ST_USER:
      break;
    case ST_PASSWORD:
      break;
    case ST_MAILFROM:
      break;
    case ST_RCPTTO:
      break;
    case ST_DATA:
      break;
    case ST_COMPOSE:
      break;
    case ST_QUIT:
      break;
    case ST_STOP:
      break;
    default:
      break;
}

The intention is that once a step is completed, the code goes to the next step. Which step that is will in this case depend on the result of eRcv

I'll advise to write functions for the steps; except for the connect, stop and compose steps, you can use something like below

/*
  send command to email server
  In:
    command
  Returns:
    email status (ES_WAITINGFORREPLY, ES_TIMEOUT, ES_FAIL or ES_OK)
*/
EMAILSTATUS sendCommand(const char *command)
{
  // keep track if we have send the command
  static bool inProgress = false;

  // if command not send yet
  if (inProgress == false)
  {
    // in case there still is data from a previous reply, get rid of it
    // this is a bit of a hack to work around the earlier mentioned flaw and probably still not 100% solid
    while (client.available() > 0)
    {
      client.read();
    }

    // send command
    client.println(command);
    // indicate that command was send
    inProgress = true;
  }

  // check reply
  EMAILSTATUS rv = eRcv();
  if (rv != ES_WAITINGFORREPLY)
  {
    inProgress = false;
  }
  return rv;
}

For connect

/*
  connect to email server
  Returns:
    email status (ES_WAITINGFORREPLY, ES_TIMEOUT, ES_FAIL, ES_CONNERR or ES_OK)
*/
EMAILSTATUS connect()
{
  // keep track if we have tried to connect and are waiting for reply
  static bool inProgress = false;

  // if not yet tried to connect
  if (inProgress == false)
  {
    if (client.connect(server, port) == 1)
    {
      Serial.println(F("connected"));
      inProgress = true;
    }
    else
    {
      Serial.println(F("connection failed"));
      return ES_CONNERR;
    }
  }

  EMAILSTATUS rv = eRcv();
  if (rv != ES_WAITINGFORREPLY)
  {
    inProgress = false;
  }
  return rv;
}

Note that this uses ES_CONNERR which you need to add to the EMAILSTATUS enum.

With those in place, we can populate most of the cases.

/*
  send email
  Returns:
    true once sending is completed or aborted, else false
*/
bool sendEmail()
{
  EMAILSTATUS rv;
  switch (emailStep)
  {
    case ST_CONNECT:
      rv = connect();
      switch (rv)
      {
        case ES_WAITINGFORREPLY:
          // keep waiting
          return false;
          break;
        case ES_TIMEOUT:
          // no reply, go to  ES_STOP to close the connection
          emailStep = ST_STOP;
          return false;
          break;
        case ES_FAIL:
          // error reply, go to ES_QUIT
          emailStep = ST_QUIT;
          return false;
          break;
        case ES_CONNERR:
          // connection error, indicate that we're done
          return true;
          break;
        case ES_OK:
          // everything OK, go to ES_HELO
          emailStep = ST_HELO;
          return false;
          break;
        default:
          Serial.println(F("Something's wrong; should not get here"));
          // a rough hack
          client.stop();
          return true;
          break;
      }
      break;

      // other cases here
      ...
      ...
      
      default:
        Serial.println(F("Something's wrong; should not get here"));
        // a rough hack
        client.stop();
        return true;
        break;
  }
}

I've changed the return type to a bool. The return value indicates if the caller (loop()) has to call the function again (false) or not (true). Depending on the return value of connect, the code can change the step to whatever is needed.

The two default cases are there to keep the compiler happy; they should not be needed. If you ever encounter the message "Something's wrong; should not get here", I was mistaken and have a bug in the code.

Below an example for all other cases except ST_COMPOSE, ST_QUIT and ST_STOP; you just need to modify the command to send and the emailStep in the ES_OK case to go to the intended next step.

    case ST_HELO:
      rv = sendCommand("EHLO 1.2.3.4");
      switch (rv)
      {
        case ES_WAITINGFORREPLY:
          // keep waiting
          break;
        case ES_TIMEOUT:
          // timeout, go to ES_STOP to close the connection
          emailStep = ST_STOP;
          break;
        case ES_FAIL:
          // error reply, go to ES_QUIT
          emailStep = ST_QUIT;
          break;
        case ES_OK:
          // everything OK, go to ST_AUTHLOGIN
          emailStep = ST_AUTHLOGIN;
          break;
        default:
          break;
      }
      // indicate to caller that we're not done yet
      return false;
      break;

For the ST_QUIT step, we don't want to keep on going back to ST_QUIT on failure and get stuck in there forever; we simply go to ST_STOP as shown below

    case ST_QUIT:
      rv = sendCommand("EHLO 1.2.3.4");
      switch (rv)
      {
        case ES_WAITINGFORREPLY:
          // keep waiting
          break;
        case ES_TIMEOUT:
          // timeout, go to ES_STOP to close the connection
          emailStep = ST_STOP;
          break;
        case ES_FAIL:
          // error reply, go to ES_QUIT
          emailStep = ST_STOP;
          break;
        case ES_OK:
          // everything OK, go to ST_AUTHLOGIN
          emailStep = ST_AUTHLOGIN;
          break;
      }
      
      // indicate to caller that we're not done yet
      return false;
      break;

For the ST_STOP case, we simply call client.stop() and indicate that we're done.

    case ST_STOP:
      client.stop();
      
      // for the next time that we want to send a mail, start from the beginning
      emailStep = ST_CONNECT;

      // indicate to caller that we're not done yet
      return true;
      break;

For the ST_COMPOSE step, you will have to write a function similar to sendCommand and call it in that case. It does not have to take an argument.

/*
  compose email
  Returns:
    email status (ES_WAITINGFORREPLY, ES_TIMEOUT, ES_FAIL or ES_OK)
*/
EMAILSTATUS compose()
{
  // keep track if we have send the command
  static bool inProgress = false;

  // if command not send yet
  if (inProgress == false)
  {
    // in case there still is data from a previous reply, get rid of it
    // this is a bit of a hack to work around the earlier mentioned flaw and probably still not 100% solid
    while (client.available() > 0)
    {
      client.read();
    }

    // send all the info here (to, from, subject, ...)
    
    // send the actual data (a message, global variables from e.g. sensors etc)
    
    // send CRLF dot CRLF to indicate end of compose
    client.print("\r\n.\r\n");

    // indicate that command was send
    inProgress = true;
  }

  // check reply
  EMAILSTATUS rv = eRcv();
  if (rv != ES_WAITINGFORREPLY)
  {
    inProgress = false;
  }
  return rv;
}

With the above implementation, there should not be a need for a call to efail in eRcv. So you can remove the complete efail function as far as I understand the code.

Continued in next post due to size limit.

And lastly you need to modify loop()

void loop()
{
  // keep track if sending is in progress.
  static bool sendingInProgress = false;

  byte inChar = Serial.read();
  if (inChar == 'e')
  {
    sendingInProgress = true;
  }

  if (sendingInProgress == true)
  {
    bool rv = sendEmail();
    if(rv == true)
    {
      Serial.println(F("Sending email success or aborted"));
      sendingInProgress = false;
    }
  }
}

Note that due to the approach, rv does not indicate success or failure. If you need a message like about that, it's the esiest to implement that in sendMail. Or rework sendMailso it can return three value using an enum that contains values for SUCCESS, ERROR and INPROGRESS.

I hope that this gets you on the right track.

dear Sir,

Thanks a lot for your reply. You are right. I have just posted the code i used as a pattern. However my code does not look that different on the very basis. I have added some extra functionality here and there, mainly for debug-reasons. The comments are in german and i didnt want to rewrite everything in english :wink:

so here is my code written in my mothertongue (time = Zeit)

//include header
#include "EMailSoftware.h"
#include "LIB/OLED_IO.h"
#include "Softwareprofile.h"


int debug = 1;
int schritt;
String Output ="schritt: ";
byte respCode;    // Variable die die Antwort des Servers ausgibt
byte thisByte;                                     // Variable 
int loopCount;
//Je nach Situation den richtigen Clienten auswählen

#include <ESP8266WiFi.h>
WiFiServer server(80);


 long timec, time1, time2;
String timems = " ms";
String times = "Systemzeit: ";
String timed = "Zeitdifferenz: ";
String TAB ="/t";
void zeitmessung()
{
  time2=(millis()-time1);
  Serial.println(timed + time2 + timems);
}

char sender[] = "xxxxx@student.jade-hs.de";  // E-Mail-Addresse des Senders
char user[] = "Projekt";                                 // user des Mail-Servers
char userb64[] = "cHJvamVrdA==";                     // User des Mail-Servers in base64 codiert
char PW[] = "projekt1";                                   // Passwort für Mail-Server
char PWb64[] = "cHJvamVrdDE=";                       // Passwort für Mail-Server in base 64 codiert
char receiver[] = "xxxx@gmx.de";            // Empfängeraddresse
char messageline1[] = "Alarm vom ESP Text geändert\n";              // Mitteilung line 1
char messageline2[] = "Alarm vom ESP line 3";         // Mitteilung line 2
char smtpcorp[] = "smtpcorp.com";                    // E-Mail-Server
int port = 2525;                                     // Port

WiFiClient client;

byte eRcv()
{
  loopCount = 0;                                  // Variable mit der die Zeit bestimmt wird....

// Funktion um sich mit dem Server zu verbinden
  time1 = millis();
  //while(!client.available())
  while(!client.available()) {                                // ....und die anschließende Funktion zum hochzählen
    delay(1);
    loopCount++;

    // if nothing received for 10 seconds, timeout
    if(loopCount > 10000) {
      client.stop();
      if(debug)
        {
          Serial.println(F("10 sec \r\nTimeout"));
        }
      return 0;
    }                                  // Beim Überlauf wird eine 0 ausgegeben
  }
  zeitmessung();
  respCode = client.peek();                 // Funktion mit der einkommende Daten ausgewertet und gespeichert werden
                                            // Funktion mit der einkommende Daten ausgelesen werden und über die serielle Schnittstelle angezeiogt werden können
  time1=millis();
  while(client.available())
  { 
    thisByte = client.read();   
    if(debug)
      {
        Serial.write(thisByte);
        //zeitmessung();
      }
  }
  zeitmessung();
  return 1;
}

int sendEmail()
{
    if(schritt==1)
    {
      thisByte = 0;
      time1=millis();
      if(client.connect( smtpcorp,port) == 1) 
      {
        if(debug)
        {
          Serial.println("connected ");
          zeitmessung();
        }
      } 
      else 
      {
        if(debug)
        {
          Serial.println("connection failed ");
          zeitmessung();
        }
      return 0;
      }
      if(!eRcv()) 
      {
        if(debug)
          {
            Serial.println("before ehlo");
          }
        return 0 ;
      }
    }

  if(schritt==2)
  {
    time1 = millis();
    client.println(F("EHLO 139.13.210.77"));                               // CMD_PROMPT: Befehl für das cmd prompt mit der jeweiligen IP-Addresse des Micro-Controllers
    if(debug)
    {
      Serial.println("Sending EHLO");                                   // Befehl wird über die serielle Verbindung übertragen und kann im serial monitor betrachtet werden
      zeitmessung();
    }
    if(!eRcv())
      {
        if(debug)
        {
          Serial.println("ehlo");
        }
      return 0 ;
      }
    time1=millis();
    client.println("auth login");                                     // Befehl für das cmd prompt -> Befehl um sich bei smtp2go anmelden zu können
    if(debug)
    {
      Serial.println(F("Sending auth login"));                             // Befehl über serielle Verbindung
      zeitmessung();
    } 
    if(!eRcv()) 
    {
      if(debug)
      {
        Serial.println("auth");
      }
      return 0 ;
    }
    time1=millis();
    client.println(userb64); //<---------User                 // base 64 codierter Name des users
    if(debug)
    {
      Serial.println(F("Sending User"));                                  // Befehl über serielle Verbindung
      zeitmessung();
    }
    if(!eRcv()) 
    {
      if(debug)
      {
        Serial.println("user");
      }
      return 0 ;
    }
  }
  if(schritt==3)
  {
    time1=millis();
    client.println(PWb64);                                  //<---------Passwort mit base64 codiert
    if(debug)
    {
      Serial.println("Sending Password");                            // Bfehl für cmd prompt -> Befehl um das Passwort eingeben zu können
      zeitmessung();
    }
    if(!eRcv())
    {
      if(debug)
      {
        Serial.println("Passwort");
      }
      return 0;
    }
  }
  if(schritt==4)
  {
    time1=millis();
    client.println(F("mail from: xxxx@student.jade-hs.de"));   // CMD-PROMPT: E-Mail-addresse von der gesendet werden soll
    if(debug)
    {
      Serial.println("sending from xxxx@student.jade-hs.de");                                  // Befehl über serielle Verbindung
      zeitmessung();
    }
    if(!eRcv()) 
      {
        if(debug)
        {
          Serial.println("email sender");
        }
        return 0 ;
      }
  }
  if(schritt==5)
  {
    time1=millis();
    client.println(F("rcpt to: xxxx@gmx.de"));                 // CMD-PROMPT: E-Mail-Addresse zu der gesendet werden soll
    if(debug)
    {
      Serial.println(F("sending to xxxxx@gmx.de"));                                    // Befehl über serielle Verbindung
      zeitmessung();
    }
    if(!eRcv() ) 
    {
      if(debug)
      {
        Serial.println("email rcpt"); 
      }
      return 0 ;
    }
  }
  if(schritt==6)
  {
    time1=millis();
    client.println(F("data"));                                          // CMD-PROMPT: Daten die versendet werden sollen
    if(debug)
    {
      Serial.println(F("Sending DATA"));                                  // Befehl über serielle Verbindung
      zeitmessung();
    }
    if(!eRcv()) 
    {
      if(debug)
      {
        Serial.println("data");
      }
      return 0 ;
    }
    time1=millis();
    client.println(F("Subject: Esp8266 email test \r \n"));  // CMD-PROMPT: Subject der E-Mail
    client.println(F("\n"));                                               // CMD-PROMPT: 2 x bestätigen
    client.println("ESP8266: Start");  
    client.println(messageline1);                       // CMD-PROMPT: line 1
    client.println(messageline2);                 // CMD-PROMPT: line 2
    client.println("ESP8266: Ende\n");  
    client.println(F("."));                                              // CMD-PROMPT: Ende der Mail
    if(debug)
    {
      Serial.println(F("Sending email"));                                 // Befehl über serielle Verbindung
      zeitmessung();
    }
  }
  if(schritt==7)
  {
    if(!eRcv()) 
    {
      if(debug)
      {
        Serial.println("aftersending");
      }
      return 0 ;
    }
    time1=millis();
    client.println(F("quit"));                                           // CMD-PROMPT: Quit
    if(debug)
      {
        Serial.println(F("Sending quit"));                                  // Befehl über serielle Verbindung
        zeitmessung();
      }
    if(!eRcv() && debug) 
    {
      Serial.println("afterQuit");
      return 0 ;
      } 
    time1=millis();
    client.stop();
  if(debug == 1)
    {
      Serial.println(F("disconnected"));                                  // Befehl über serielle Verbindung
      zeitmessung();
    }
    schritt=0;
    return 1;
  }
  if(schritt!=0)
  {
    schritt+=1;
    if(debug == 1)
    {
      Serial.println(Output + schritt);
    }  
  }
}

// Funktion mit der eine E-Mail auf Knopfdruck versand wird

void PUSH_AND_SEND( void )
{
  unsigned char c;

    c = pollkey_();
    if( c == 0x88 )                      // unten links
    {
      schritt=1;
      Serial.println(Output + schritt);
      server.begin();                   // Verbindung mit Server aufbauen
    }
    sendEmail();
      
}

And this is what you can see in the serial monitor

schritt: 1
connected
Zeitdifferenz: 349 ms
Zeitdifferenz: 203 ms
220 smtpcorp.com ESMTP Exim 4.91 Mon, 21 Jan 2019 10:09:41 +0000
Zeitdifferenz: 0 ms
schritt: 2
Sending EHLO
Zeitdifferenz: 2502 ms
Zeitdifferenz: 48 ms
250-smtpcorp.com Hello 139.13.210.77 [139.13.210.78]
250-SIZE 52428800
250-8BITMIME
250-DSN
250-PIPELINING
250-AUTH CRAM-MD5 PLAIN LOGIN
250-CHUNKING
250-STARTTLS
250-PRDR
250 HELP
Zeitdifferenz: 12 ms
Sending auth login
Zeitdifferenz: 306 ms
Zeitdifferenz: 2 ms
334 VXNlcm5hbWU6
Zeitdifferenz: 0 ms
Sending User
Zeitdifferenz: 306 ms
Zeitdifferenz: 0 ms
334 UGFzc3dvcmQ6
Zeitdifferenz: 1 ms
schritt: 3
Sending Password
Zeitdifferenz: 302 ms
Zeitdifferenz: 27 ms
235 Authentication succeeded
Zeitdifferenz: 0 ms
schritt: 4
sending from xxx@student.jade-hs.de
Zeitdifferenz: 4582 ms
Zeitdifferenz: 51 ms
250 OK
Zeitdifferenz: 0 ms
schritt: 5
sending to xxxx@gmx.de
Zeitdifferenz: 3928 ms
Zeitdifferenz: 98 ms
250 Accepted xxx@gmx.de
Zeitdifferenz: 0 ms
schritt: 6
Sending DATA
Zeitdifferenz: 692 ms
Zeitdifferenz: 50 ms
354 Enter message, ending with "." on a line by itself
Zeitdifferenz: 1 ms
Sending email
Zeitdifferenz: 5704 ms
schritt: 7
Zeitdifferenz: 80 ms
250 OK id=1glWWg-095GLA-Sd
Zeitdifferenz: 0 ms
Sending quit
Zeitdifferenz: 692 ms
Zeitdifferenz: 2 ms
221 smtpcorp.com closing connection
Zeitdifferenz: 1 ms
disconnected
Zeitdifferenz: 0 ms

New client: 1 61.219.11.151:63041Timeout
Done 1
Disconnect 1

i am currently trying to rewrite my programmcode in the way you have advised it. However i got some compilation problems like: "no matching function for call to 'WiFiClient::connect(WiFiServer&, int&)'" and i am not sure how to fix it yet.

I am also not sure if i got everything right. The code is quite big now and it is not possible to post it in here

Hello again,

i have problems with the following line

rv = sendCommand("EHLO 1.2.3.4");

it seems that the compiler is not able to find this command. however i can't rewrite this line using "serial.println()" since rv has the type of EMAILSTATUS. Which library do i need to include this function?

There is no library for what I provided. EMAILSTATUS is given in reply #9 and sendCommand in reply #10.