xreef / EMailSender

Arduino, esp32, Esp8266 EMailSender with Arduino IDE, simple library to send email via smtp with attachments.
https://www.mischianti.org/category/my-libraries/emailsender-send-email-with-attachments/
MIT License
74 stars 26 forks source link

Needs more than 40 seconds to send. Any ideas why? #26

Closed BenSeventy9 closed 2 years ago

BenSeventy9 commented 2 years ago

Serial Monitor:

...............................
Connection: ESTABLISHED
Got IP address: 192.168.0.23
Sending status: 
1
0
Message sent!
Time for sending: 42.47 seconds

My code: Credentials and mail replaced by "***"

/*
   EMailSender library for Arduino, esp8266 and esp32
   Simple esp8266 Gmail send example

   https://www.mischianti.org/category/my-libraries/emailsender-send-email-with-attachments/

*/

#include "Arduino.h"
#include <EMailSender.h>
#include <ESP8266WiFi.h>

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

uint8_t connection_state = 0;
uint16_t reconnect_interval = 2000;

EMailSender emailSend("***", "***", "***", "***", "mail.gmx.net", 465);

uint8_t WiFiConnect(const char* nSSID = nullptr, const char* nPassword = nullptr)
{
  static uint16_t attempt = 0;
  Serial.print("Connecting to ");
  if (nSSID) {
    WiFi.begin(nSSID, nPassword);
    Serial.println(nSSID);
  }

  uint8_t i = 0;
  while (WiFi.status() != WL_CONNECTED && i++ < 50)
  {
    delay(200);
    Serial.print(".");
  }
  ++attempt;
  Serial.println("");
  if (i == 51) {
    Serial.print("Connection: TIMEOUT on attempt: ");
    Serial.println(attempt);
    if (attempt % 2 == 0)
      Serial.println("Check if access point available or SSID and Password\r\n");
    return false;
  }
  Serial.println("Connection: ESTABLISHED");
  Serial.print("Got IP address: ");
  Serial.println(WiFi.localIP());
  return true;
}

void Awaits()
{
  uint32_t ts = millis();
  while (!connection_state)
  {
    delay(50);
    if (millis() > (ts + reconnect_interval) && !connection_state) {
      connection_state = WiFiConnect();
      ts = millis();
    }
  }
}

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

  connection_state = WiFiConnect(ssid, password);
  if (!connection_state) // if not connected to WIFI
    Awaits();          // constantly trying to connect

  emailSend.setPublicIpDescriptor("WemosSensor");
  //emailSend.setIsSecure(true);
  emailSend.setEHLOCommand(true);

  EMailSender::EMailMessage message;
  message.mime = MIME_TEXT_PLAIN;
  message.subject = "Soggetto";
  message.message = "Ciao come stai<br>io bene.<br>www.mischianti.org";

  uint32_t start = millis();

  EMailSender::Response resp = emailSend.send("***", message);

  Serial.println("Sending status: ");

  Serial.println(resp.status);
  Serial.println(resp.code);
  Serial.println(resp.desc);

  uint32_t end = millis();

  Serial.print(F("Time for sending: "));
  Serial.print((double)(end - start) / 1000, 2);
  Serial.println(F(" seconds"));
}

void loop() {}
xreef commented 2 years ago

It's very strange, but I think you have some network delay, try to put the router and device close. Bye Renzo

salasidis commented 2 years ago

Maybe the delay is on the line if (this->useEHLO == true) { for (int i = 0; i<=11; i++) awaitSMTPResponse(client); }

If the server sends fewer outputs, it still waits for 6. I will change the code on my end to stop the loop when there is a call with a delay occuring, and see if it helps on my end.

xreef commented 2 years ago

Hi @salasidis, If there is a timeout the email is not sent with a timeout error. Bye Renzo

BenSeventy9 commented 2 years ago

When I use a Gmail address it sends within 2s. It isn't caused by network delay. I send it only once when battery is low so I can live with those 40 seconds.

xreef commented 2 years ago

Hi Ben, can you enable the DEBUG and send me the result.

#define EMAIL_SENDER_DEBUG

https://github.com/xreef/EMailSender/blob/master/EMailSenderKey.h#L43

Bye Renzo

BenSeventy9 commented 2 years ago

`............................... Connection: ESTABLISHED Got IP address: 192.168.1.80 ONLY ONE RECIPIENTmiltiple destination and attachments Insecure client:0 MFLN supported: yes mail.gmx.net 465 220 gmx.net (mrgmx005) Nemesis ESMTP Service ready

EHLO WemosSensor: 250-gmx.net Hello WemosSensor: [84.226.107.152]

250-8BITMIME

250-AUTH LOGIN PLAIN

250 SIZE 69920427

AUTH LOGIN: 334 VXNlcm5hbWU6

Encoding hidden@gmx.net 18 hidden Encoding hidden@gmx.net 18 334 UGFzc3dvcmQ6

Encoding hidden 24 hidden Encoding hidden 24 235 Authentication succeeded

MAIL FROM: *hidden*@gmx.net 250 Requested mail action okay, completed

RCPT TO: *hidden*@gmx.ch 250 OK

DATA: 354 Start mail input; end with .

Message end 250 Requested mail action okay, completed: id=1MLzBj-1oP2pU2fyb-00Hv5c

221 gmx.net Service closing transmission channel

Sending status: 1 0 Message sent! Time for sending: 43.00 seconds `

xreef commented 2 years ago

There is a point that needs more time?

BenSeventy9 commented 2 years ago

After "250 SIZE 69920427" starts the delay until "AUTH LOGIN:". Hope that helps

BenSeventy9 commented 2 years ago

I played a bit around and changed the loop to 2: if (this->useEHLO == true) { for (int i = 0; i<=2; i++) awaitSMTPResponse(client); } Output: 250 Requested mail action okay, completed: id=1MWzfv-1o9ceG3VCj-00XI1S

221 gmx.net Service closing transmission channel

Sending status: 1 0 Message sent! Time for sending: 2.40 seconds

Looks like salasidis was right!

salasidis commented 2 years ago

I added a test code on my end,

I time the rime between successive 250-×××

If the time of any one is greater than a few seconds, I presume there are no more left, and I proceed to an auth login

This way the delay happens just once, and is independent of the number of 250×× replies from the server.

Otherwise there wad a risk of interviewing the 250××× responses with the auth login going out, or too long delay, if exoect more 250s than there actually are.

-------- Original message -------- From: BenSeventy9 @.> Date: 2022-07-01 08:39 (GMT-05:00) To: xreef/EMailSender @.> Cc: rsalasidis @.>, Mention @.> Subject: Re: [xreef/EMailSender] Needs more than 40 seconds to send. Any ideas why? (Issue #26)

After "250 SIZE 69920427" starts the delay until "AUTH LOGIN:". Hope that helps

— Reply to this email directly, view it on GitHubhttps://github.com/xreef/EMailSender/issues/26#issuecomment-1172303032, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AK5VYZODOIQ3U7PURPV3OFDVR3RHHANCNFSM5ZMZRLZQ. You are receiving this because you were mentioned.Message ID: @.***>

BenSeventy9 commented 2 years ago

I added a test code on my end, I time the rime between successive 250-××× If the time of any one is greater than a few seconds, I presume there are no more left, and I proceed to an auth login This way the delay happens just once, and is independent of the number of 250×× replies from the server. Otherwise there wad a risk of interviewing the 250××× responses with the auth login going out, or too long delay, if exoect more 250s than there actually are.

Do you have some code snipped for me?

salasidis commented 2 years ago

In emailSender.cpp I did the following. I also attached the whole file.

Let me know if helpful. Thanks

response = awaitSMTPResponse(client, "220", "Connection Error"); if (!response.status) { client.flush(); client.stop(); return response; }

String commandHELO = "HELO"; if (this->useEHLO == true) { commandHELO = "EHLO"; } String helo = commandHELO + " "+/String(publicIPDescriptor)/ smtp_server /+": "/; DEBUG_PRINTLN(helo); client.println(helo);

response = awaitSMTPResponse(client, "250", "Identification error"); DEBUG_PRINTLN(response.status); if (!response.status) { client.flush(); client.stop(); return response; }

loopTime1 = millis(); DEBUG_PRINTLN(loopTime1); if (this->useEHLO == true) { for (int i = 0; i<=20; i++) { awaitSMTPResponse(client); loopTime2 = millis(); DEBUG_PRINTLN(loopTime2); if ((loopTime2 - loopTime1) > 2500) { break; } else { loopTime1 = loopTime2; } } } DEBUG_PRINTLN("End of awaitSMTPResponse");

From: BenSeventy9 @.> Sent: July 1, 2022 16:04 To: xreef/EMailSender @.> Cc: rsalasidis @.>; Mention @.> Subject: Re: [xreef/EMailSender] Needs more than 40 seconds to send. Any ideas why? (Issue #26)

I added a test code on my end, I time the rime between successive 250-××× If the time of any one is greater than a few seconds, I presume there are no more left, and I proceed to an auth login This way the delay happens just once, and is independent of the number of 250×× replies from the server. Otherwise there wad a risk of interviewing the 250××× responses with the auth login going out, or too long delay, if exoect more 250s than there actually are.

Do you have some code snipped for me?

— Reply to this email directly, view it on GitHubhttps://github.com/xreef/EMailSender/issues/26#issuecomment-1172676055, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AK5VYZMGWYZLF4SOYO4YXF3VR5FMFANCNFSM5ZMZRLZQ. You are receiving this because you were mentioned.Message ID: @.**@.>>

/*

include "EMailSender.h"

include

//#include //#include

//#define SD SPIFFS

// BASE64 ----------------------------------------------------------- const char PROGMEM b64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/";

define encode64(arr) encode64_f(arr,strlen(arr))

inline void a3_to_a4(unsigned char a4, unsigned char a3) { a4[0] = (a3[0] & 0xfc) >> 2; a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); a4[3] = (a3[2] & 0x3f); }

int base64_encode(char output, char input, int inputLen) { int i = 0, j = 0; int encLen = 0; unsigned char a3[3]; unsigned char a4[4];

while (inputLen--) { a3[i++] = *(input++); if (i == 3) { a3_to_a4(a4, a3);

  for (i = 0; i < 4; i++) {
    output[encLen++] = pgm_read_byte(&b64_alphabet[a4[i]]);
  }

  i = 0;
}

}

if (i) { for (j = i; j < 3; j++) { a3[j] = '\0'; }

a3_to_a4(a4, a3);

for (j = 0; j < i + 1; j++) {
  output[encLen++] = pgm_read_byte(&b64_alphabet[a4[j]]);
}

while ((i++ < 3)) {
  output[encLen++] = '=';
}

} output[encLen] = '\0'; return encLen; }

int base64_enc_length(int plainLen) { int n = plainLen; return (n + 2 - ((n + 2) % 3)) / 3 * 4; }

const char encode64_f(char input, uint8_t len) { // encoding

DEBUG_PRINTLN(F("Encoding"));

DEBUG_PRINTLN(input);
DEBUG_PRINTLN(len);

//int encodedLen = base64_enc_length(len); static char encoded[256]; // note input is consumed in this step: it will be empty afterwards base64_encode(encoded, input, len); return encoded; }

// END BASE64 ---------------------------------------------------------

EMailSender::EMailSender(const char email_login, const char email_password, const char email_from, const char name_from , const char smtp_server, uint16_t smtp_port) { this->setEMailLogin(email_login); this->setEMailFrom(email_from); this->setEMailPassword(email_password); this->setSMTPServer(smtp_server); this->setSMTPPort(smtp_port); this->setNameFrom(name_from); // this->isSecure = isSecure; } EMailSender::EMailSender(const char email_login, const char email_password, const char email_from, const char* smtp_server, uint16_t smtp_port) { this->setEMailLogin(email_login); this->setEMailFrom(email_from); this->setEMailPassword(email_password); this->setSMTPServer(smtp_server); this->setSMTPPort(smtp_port);

// this->isSecure = isSecure; }

EMailSender::EMailSender(const char email_login, const char email_password, const char email_from, const char name_from ) { this->setEMailLogin(email_login); this->setEMailFrom(email_from); this->setEMailPassword(email_password); this->setNameFrom(name_from); this->setNameFrom(name_from);

// this->isSecure = isSecure; } EMailSender::EMailSender(const char email_login, const char email_password, const char* email_from) { this->setEMailLogin(email_login); this->setEMailFrom(email_from); this->setEMailPassword(email_password);

// this->isSecure = isSecure; }

EMailSender::EMailSender(const char email_login, const char email_password){ this->setEMailLogin(email_login); this->setEMailFrom(email_login); this->setEMailPassword(email_password);

// this->isSecure = isSecure; }

void EMailSender::setSMTPPort(uint16_t smtp_port){ this->smtp_port = smtp_port; }; void EMailSender::setSMTPServer(const char* smtp_server){ delete [] this->smtp_server; this->smtp_server = new char[strlen(smtp_server)+1]; strcpy(this->smtp_server, smtp_server); };

void EMailSender::setEMailLogin(const char email_login){ delete [] this->email_login; this->email_login = new char[strlen(email_login)+1]; strcpy(this->email_login, email_login); }; void EMailSender::setEMailFrom(const char email_from){ delete [] this->email_from; this->email_from = new char[strlen(email_from)+1]; strcpy(this->email_from, email_from); }; void EMailSender::setNameFrom(const char name_from){ delete [] this->name_from; this->name_from = new char[strlen(name_from)+1]; strcpy(this->name_from, name_from); }; void EMailSender::setEMailPassword(const char email_password){ delete [] this->email_password; this->email_password = new char[strlen(email_password)+1]; strcpy(this->email_password, email_password); };

void EMailSender::setIsSecure(bool isSecure) { this->isSecure = isSecure; }

ifdef SSLCLIENT_WRAPPER

EMailSender::Response EMailSender::awaitSMTPResponse(SSLClient &client, const char resp, const char respDesc, uint16_t timeOut) { EMailSender::Response response; uint32_t ts = millis(); while (!client.available()) { if (millis() > (ts + timeOut)) { response.code = F("1"); response.desc = String(respDesc) + "! " + F("SMTP Response TIMEOUT!"); response.status = false;

        return response;
    }
}
_serverResponce = client.readStringUntil('\n');

DEBUG_PRINTLN(_serverResponce);
if (resp && _serverResponce.indexOf(resp) == -1){
    response.code = resp;
    response.desc = respDesc +String(" (") + _serverResponce + String(")");
    response.status = false;

    return response;
}

response.status = true;
return response;

}

else

EMailSender::Response EMailSender::awaitSMTPResponse(EMAIL_NETWORK_CLASS &client, const char resp, const char respDesc, uint16_t timeOut) { EMailSender::Response response; uint32_t ts = millis(); while (!client.available()) { if (millis() > (ts + timeOut)) { response.code = F("1"); response.desc = String(respDesc) + "! " + F("SMTP Response TIMEOUT!"); response.status = false; return response; } } _serverResponce = client.readStringUntil('\n');

DEBUG_PRINTLN("Server Response = ");
DEBUG_PRINTLN(_serverResponce);
if (resp && _serverResponce.indexOf(resp) == -1){
    response.code = resp;
    response.desc = respDesc +String(" (") + _serverResponce + String(")");
    response.status = false;
    return response;
}

response.status = true;
return response;

}

endif

static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; void encodeblock(unsigned char in[3],unsigned char out[4],int len) { out[0]=cb64[in[0]>>2]; out[1]=cb64[((in[0]&0x03)<<4)|((in[1]&0xF0)>>4)]; out[2]=(unsigned char) (len>1 ? cb64[((in[1]&0x0F)<<2)|((in[2]&0xC0)>>6)] : '='); out[3]=(unsigned char) (len>2 ? cb64[in[2]&0x3F] : '='); }

ifdef ENABLE_ATTACHMENTS

#ifdef STORAGE_EXTERNAL_ENABLED
    #if (defined(DIFFERENT_FILE_MANAGE) && defined(EMAIL_FILE_EX)) || !defined(STORAGE_INTERNAL_ENABLED)
        #ifdef SSLCLIENT_WRAPPER
                    void encode(EMAIL_FILE_EX *file, SSLClient *client) {
                    unsigned char in[3],out[4];
                    int i,len,blocksout=0;

                    while (file->available()!=0) {
                    len=0;
                        for (i=0;i<3;i++){
                            in[i]=(unsigned char) file->read();
                                if (file->available()!=0) len++;
                                        else in[i]=0;
                        }
                        if (len){
                            encodeblock(in,out,len);
                    //         for(i=0;i<4;i++) client->write(out[i]);
                            client->write(out, 4);
                            blocksout++; }
                        if (blocksout>=19||file->available()==0){
                            if (blocksout) {
                                client->print("\r\n");
                            }
                            blocksout=0;
                        }
                    }
                    }

        #else
                void encode(EMAIL_FILE_EX *file, EMAIL_NETWORK_CLASS *client) {
                    unsigned char in[3],out[4];
                    int i,len,blocksout=0;

                    while (file->available()!=0) {
                    len=0;
                        for (i=0;i<3;i++){
                            in[i]=(unsigned char) file->read();
                                if (file->available()!=0) len++;
                                        else in[i]=0;
                        }
                        if (len){
                            encodeblock(in,out,len);
                    //         for(i=0;i<4;i++) client->write(out[i]);
                            client->write(out, 4);
                            blocksout++; }
                        if (blocksout>=19||file->available()==0){
                            if (blocksout) {
                                client->print("\r\n");
                            }
                            blocksout=0;
                        }
                    }
                    }
        #endif

    #endif
#endif
#ifdef STORAGE_INTERNAL_ENABLED
    #if defined(DIFFERENT_FILE_MANAGE) || (!defined(DIFFERENT_FILE_MANAGE) && defined(EMAIL_FILE)) || !defined(STORAGE_EXTERNAL_ENABLED)

        #ifdef SSLCLIENT_WRAPPER
                void encode(EMAIL_FILE *file, SSLClient *client) {
                 unsigned char in[3],out[4];
                 int i,len,blocksout=0;

                 while (file->available()!=0) {
                   len=0;
                     for (i=0;i<3;i++){
                           in[i]=(unsigned char) file->read();
                               if (file->available()!=0) len++;
                                     else in[i]=0;
                     }
                     if (len){
                         encodeblock(in,out,len);
                //         for(i=0;i<4;i++) client->write(out[i]);
                         client->write(out, 4);
                         blocksout++; }
                     if (blocksout>=19||file->available()==0){
                         if (blocksout) {
                             client->print("\r\n");
                         }
                         blocksout=0;
                     }
                  }
                }

        #else
                void encode(EMAIL_FILE *file, EMAIL_NETWORK_CLASS *client) {
                 unsigned char in[3],out[4];
                 int i,len,blocksout=0;

                 while (file->available()!=0) {
                   len=0;
                     for (i=0;i<3;i++){
                           in[i]=(unsigned char) file->read();
                               if (file->available()!=0) len++;
                                     else in[i]=0;
                     }
                     if (len){
                         encodeblock(in,out,len);
                //         for(i=0;i<4;i++) client->write(out[i]);
                         client->write(out, 4);
                         blocksout++; }
                     if (blocksout>=19||file->available()==0){
                         if (blocksout) {
                             client->print("\r\n");
                         }
                         blocksout=0;
                     }
                  }
                }
        #endif
    #endif
#endif

endif

const char toCharArray(String arr[], int num) { // If we ever alloc with new with have to delete const char buffer = new const char*[num];

for(int i = 0; i < num; i++) {
    buffer[i] = arr[i].c_str();
}

return buffer;

} const char* toCharArray(char arr[], int num) { // If we ever alloc with new with have to delete const char* buffer = new const char[num];

for(int i = 0; i < num; i++) {
    buffer[i] = arr[i];
}

return buffer;

}

EMailSender::Response EMailSender::send(char tos[], byte sizeOfTo, EMailMessage &email, Attachments attachments) { return send(toCharArray(tos, sizeOfTo), sizeOfTo, 0, 0, email, attachments); } EMailSender::Response EMailSender::send(char tos[], byte sizeOfTo, byte sizeOfCc, EMailMessage &email, Attachments attachments) { return send(toCharArray(tos, sizeOfTo+sizeOfCc), sizeOfTo, sizeOfCc, 0, email, attachments); } EMailSender::Response EMailSender::send(char* tos[], byte sizeOfTo, byte sizeOfCc,byte sizeOfCCn, EMailMessage &email, Attachments attachments){ return send(toCharArray(tos, sizeOfTo+sizeOfCc+sizeOfCCn), sizeOfTo, sizeOfCc, sizeOfCCn, email, attachments); }

EMailSender::Response EMailSender::send(String to, EMailMessage &email, Attachments attachments){ DEBUG_PRINT(F("ONLY ONE RECIPIENT"));

const char* arrEmail[] =  {to.c_str()};
return send(arrEmail, 1, email, attachments);

}

EMailSender::Response EMailSender::send(String tos[], byte sizeOfTo, EMailMessage &email, Attachments attachments) { return send(toCharArray(tos, sizeOfTo), sizeOfTo, 0, 0, email, attachments); }

EMailSender::Response EMailSender::send(String tos[], byte sizeOfTo, byte sizeOfCc, EMailMessage &email, Attachments attachments) { return send(toCharArray(tos, sizeOfTo+sizeOfCc), sizeOfTo, sizeOfCc, 0, email, attachments); }

EMailSender::Response EMailSender::send(String tos[], byte sizeOfTo, byte sizeOfCc,byte sizeOfCCn, EMailMessage &email, Attachments attachments){ return send(toCharArray(tos, sizeOfTo+sizeOfCc+sizeOfCCn), sizeOfTo, sizeOfCc, sizeOfCCn, email, attachments); }

EMailSender::Response EMailSender::send(const char* to, EMailMessage &email, Attachments attachments){ DEBUG_PRINT(F("ONLY ONE RECIPIENT"));

const char* arrEmail[] =  {to};
return send(arrEmail, 1, email, attachments);

}

EMailSender::Response EMailSender::send(const char* to[], byte sizeOfTo, EMailMessage &email, Attachments attachments) { DEBUG_PRINTLN(F("miltiple destination and attachments")); return send(to, sizeOfTo, 0, email, attachments); }

EMailSender::Response EMailSender::send(const char* to[], byte sizeOfTo, byte sizeOfCc, EMailMessage &email, Attachments attachments) { return send(to, sizeOfTo, sizeOfCc, 0, email, attachments); }

ifdef SSLCLIENT_WRAPPER

ifdef PUT_OUTSIDE_SCOPE_CLIENT_DECLARATION

// Initialize the SSL client library
// We input an EthernetClient, our trust anchors, and the analog pin
EMAIL_NETWORK_CLASS base_client;
SSLClient client(base_client, TAs, (size_t)TAs_NUM, ANALOG_PIN, 2);

else

#error "You must put outside scope the client declaration if you want use SSLClient!"

endif

else

#ifdef PUT_OUTSIDE_SCOPE_CLIENT_DECLARATION
    EMAIL_NETWORK_CLASS client;
#endif

endif

EMailSender::Response EMailSender::send(const char* to[], byte sizeOfTo, byte sizeOfCc,byte sizeOfCCn, EMailMessage &email, Attachments attachments) { unsigned long loopTime1, loopTime2;

ifdef SSLCLIENT_WRAPPER

DEBUG_PRINTLN(F("SSLClient active!"));

else

#ifndef PUT_OUTSIDE_SCOPE_CLIENT_DECLARATION
  EMAIL_NETWORK_CLASS client;
#endif

DEBUG_PRINT(F("Insecure client:")); DEBUG_PRINTLN(this->isSecure);

#if (EMAIL_NETWORK_TYPE == NETWORK_ESP8266 || EMAIL_NETWORK_TYPE == NETWORK_ESP8266_242)
    #ifndef ARDUINO_ESP8266_RELEASE_2_4_2
      if (this->isSecure == false){
          client.setInsecure();
          bool mfln = client.probeMaxFragmentLength(this->smtp_server, this->smtp_port, 512);

          DEBUG_PRINT("MFLN supported: ");
          DEBUG_PRINTLN(mfln?"yes":"no");

          if (mfln) {
              client.setBufferSizes(512, 512);
          }
      }
    #endif
#elif (EMAIL_NETWORK_TYPE == NETWORK_ESP32)
//    String coreVersion = String(ESP.getSdkVersion());
//    uint8_t firstdot = coreVersion.indexOf('.');
//
//    DEBUG_PRINTLN(coreVersion.substring(1, coreVersion.indexOf('.', firstdot+1)).toFloat());
//    DEBUG_PRINTLN(coreVersion.substring(1, coreVersion.indexOf('.', firstdot+1)).toFloat() >= 3.3f);
//    if (coreVersion.substring(1, coreVersion.indexOf('.', firstdot+1)).toFloat() >= 3.3f) {
//        client.setInsecure();
//    }
    #include <core_version.h>
    #if ((!defined(ARDUINO_ESP32_RELEASE_1_0_4)) && (!defined(ARDUINO_ESP32_RELEASE_1_0_3)) && (!defined(ARDUINO_ESP32_RELEASE_1_0_2)))
          client.setInsecure();
    #endif
#endif

endif

EMailSender::Response response;

DEBUG_PRINTLN(this->smtp_server); DEBUG_PRINTLN(this->smtp_port);

if(!client.connect(this->smtp_server, this->smtp_port)) { response.desc = F("Could not connect to mail server"); response.code = F("2"); response.status = false;

  client.flush();
  client.stop();

  return response;

}

response = awaitSMTPResponse(client, "220", "Connection Error"); if (!response.status) { client.flush(); client.stop(); return response; }

String commandHELO = "HELO"; if (this->useEHLO == true) { commandHELO = "EHLO"; } String helo = commandHELO + " "+/String(publicIPDescriptor)/ smtp_server /+": "/; DEBUG_PRINTLN(helo); client.println(helo);

response = awaitSMTPResponse(client, "250", "Identification error"); DEBUG_PRINTLN(response.status); if (!response.status) { client.flush(); client.stop(); return response; }

loopTime1 = millis(); DEBUG_PRINTLN(loopTime1); if (this->useEHLO == true) { for (int i = 0; i<=20; i++) { awaitSMTPResponse(client); loopTime2 = millis(); DEBUG_PRINTLN(loopTime2); if ((loopTime2 - loopTime1) > 2500) { break; } else { loopTime1 = loopTime2; } } } DEBUG_PRINTLN("End of awaitSMTPResponse");

if (useAuth){ if (this->isSASLLogin == true){

      int size = 1 + strlen(this->email_login)+ strlen(this->email_password)+2;
      char * logPass = (char *) malloc(size);

// strcpy(logPass, " "); // strcat(logPass, this->email_login); // strcat(logPass, " "); // strcat(logPass, this->email_password);

// String logPass; int maincont = 0;

      logPass[maincont++] = ' ';
      logPass[maincont++] = (char) 0;

      for (unsigned int i = 0;i<strlen(this->email_login);i++){
          logPass[maincont++] = this->email_login[i];
      }
      logPass[maincont++] = (char) 0;
      for (unsigned int i = 0;i<strlen(this->email_password);i++){
          logPass[maincont++] = this->email_password[i];
      }

// strcpy(logPass, "\0"); // strcat(logPass, this->email_login); // strcat(logPass, "\0"); // strcat(logPass, this->email_password);

      String auth = "AUTH PLAIN "+String(encode64_f(logPass, size));

// String auth = "AUTH PLAIN "+String(encode64(logPass)); DEBUG_PRINTLN(auth); client.println(auth); }else{ DEBUG_PRINTLN(F("AUTH LOGIN:")); client.println(F("AUTH LOGIN")); awaitSMTPResponse(client);

      DEBUG_PRINTLN(encode64(this->email_login));
      client.println(encode64(this->email_login));
      awaitSMTPResponse(client);

      DEBUG_PRINTLN(encode64(this->email_password));
      client.println(encode64(this->email_password));
  }
  response = awaitSMTPResponse(client, "235", "SMTP AUTH error");
  if (!response.status) {
      client.flush();
      client.stop();
      return response;
  }

} DEBUG_PRINT(F("MAIL FROM: <")); DEBUG_PRINT(this->email_from); DEBUG_PRINTLN(F(">"));

client.print(F("MAIL FROM: <")); client.print(this->email_from); client.println(F(">")); awaitSMTPResponse(client);

// String rcpt = "RCPT TO: <" + String(to) + '>'; // // DEBUG_PRINTLN(rcpt); // client.println(rcpt);

int cont; for (cont=0;cont<(sizeOfTo+sizeOfCc+sizeOfCCn);cont++){ DEBUG_PRINT(F("RCPT TO: <")); DEBUG_PRINT(to[cont]); DEBUG_PRINTLN(F(">"));

  client.print(F("RCPT TO: <"));
  client.print(to[cont]);
  client.println(F(">"));
  awaitSMTPResponse(client);

}

DEBUG_PRINTLN(F("DATA:")); client.println(F("DATA"));

response = awaitSMTPResponse(client, "354", "SMTP DATA error"); if (!response.status) { client.flush(); client.stop(); return response; }

// client.println("From: <" + String(this->email_from) + '>');

client.print(F("From: ")); if (this->name_from){ client.print(this->name_from); } client.print(F(" <")); client.print(this->email_from); client.println(F(">"));

// client.println("To: <" + String(to) + '>');

client.print(F("To: ")); for (cont=0;cont<sizeOfTo;cont++){ client.print(F("<")); client.print(to[cont]); client.print(">"); if (cont!=sizeOfTo-1){ client.print(","); } } client.println();

if (sizeOfCc>0){ client.print(F("Cc: ")); for (;cont<sizeOfTo+sizeOfCc;cont++){ client.print(F("<")); client.print(to[cont]); client.print(">"); if (cont!=sizeOfCc-1){ client.print(","); } } client.println(); }

if (sizeOfCCn>0){ client.print(F("CCn: ")); for (;cont<sizeOfTo+sizeOfCc+sizeOfCCn;cont++){ client.print(F("<")); client.print(to[cont]); client.print(">"); if (cont!=sizeOfCCn-1){ client.print(","); } } client.println(); }

client.print(F("Subject: ")); client.println(email.subject);

// client.println(F("Mime-Version: 1.0"));

client.println(F("MIME-Version: 1.0")); client.println(F("Content-Type: Multipart/mixed; boundary=frontier"));

client.println(F("--frontier"));

client.print(F("Content-Type: "));
client.print(email.mime);
client.println(F("; charset=\"UTF-8\""));

// client.println(F("Content-Type: text/html; charset=\"UTF-8\"")); client.println(F("Content-Transfer-Encoding: 7bit")); client.println(); if (email.mime==F("text/html")){ // String body = "<!DOCTYPE html><html lang=\"en\">" + String(email.message) + "";

  client.print(F("<!DOCTYPE html><html lang=\"en\">"));
  client.print(email.message);
  client.println(F("</html>"));

// client.println(body); }else{ client.println(email.message); } client.println();

ifdef STORAGE_INTERNAL_ENABLED

bool spiffsActive = false;

endif

ifdef STORAGE_EXTERNAL_ENABLED

bool sdActive = false;

endif

if defined(ENABLE_ATTACHMENTS) && (defined(STORAGE_EXTERNAL_ENABLED) || defined(STORAGE_INTERNAL_ENABLED))

// if ((sizeof(attachs) / sizeof(attachs[0]))>0){ if (sizeof(attachments)>0 && attachments.number>0){

  DEBUG_PRINT(F("Array: "));

// for (int i = 0; i<(sizeof(attachs) / sizeof(attachs[0])); i++){ for (int i = 0; i<attachments.number; i++){ uint8_t tBuf[64];

      if (attachments.fileDescriptor[i].url.length()==0){
          EMailSender::Response response;
          response.code = F("400");
          response.desc = "Error no filename specified for the file "+attachments.fileDescriptor[i].filename;
          response.status = false;
          client.flush();
          client.stop();

          return response;
      }
      if (attachments.fileDescriptor[i].mime.length()==0){
          EMailSender::Response response;
          response.code = F("400");
          response.desc = "Error no mime type specified for the file "+attachments.fileDescriptor[i].url;
          response.status = false;
          client.flush();
          client.stop();

          return response;
      }
      if (attachments.fileDescriptor[i].filename.length()==0){
          EMailSender::Response response;
          response.code = F("400");
          response.desc = "Error no filename specified for the file "+attachments.fileDescriptor[i].url;
          response.status = false;
          client.flush();
          client.stop();

          return response;
      }

      DEBUG_PRINTLN(attachments.fileDescriptor[i].filename);
      DEBUG_PRINTLN(F("--frontier"));
      client.println(F("--frontier"));
      DEBUG_PRINTLN(F("Content-Type: "));
      client.print(F("Content-Type: "));
      DEBUG_PRINTLN(attachments.fileDescriptor[i].mime);
      client.print(attachments.fileDescriptor[i].mime);
      DEBUG_PRINTLN(F("; charset=\"UTF-8\""));
      client.println(F("; charset=\"UTF-8\""));

      if (attachments.fileDescriptor[i].encode64){
          client.println(F("Content-Transfer-Encoding: base64"));
      }

      client.print(F("Content-Disposition: attachment; filename="));
      client.print(attachments.fileDescriptor[i].filename);
      client.println(F("\n"));

        int clientCount = 0;

ifdef STORAGE_INTERNAL_ENABLED

        if (attachments.fileDescriptor[i].storageType==EMAIL_STORAGE_TYPE_SPIFFS ||
            attachments.fileDescriptor[i].storageType==EMAIL_STORAGE_TYPE_LITTLE_FS ||
            attachments.fileDescriptor[i].storageType==EMAIL_STORAGE_TYPE_SPIFM ||
            attachments.fileDescriptor[i].storageType==EMAIL_STORAGE_TYPE_FFAT){
#ifdef OPEN_CLOSE_INTERNAL
            if (!INTERNAL_STORAGE_CLASS.exists(attachments.fileDescriptor[i].url.c_str())){
                #if (INTERNAL_STORAGE == STORAGE_SPIFM)
                Adafruit_FlashTransport_SPI flashTransport(SPIFM_CS_PIN, SPI); // Set CS and SPI interface
                Adafruit_SPIFlash flash(&flashTransport);

                      // Initialize flash library and check its chip ID.
                if (!flash.begin()) {
                    EMailSender::Response response;
                      response.code = F("500");
                      response.desc = F("Error, failed to initialize flash chip!");
                      response.status = false;
                      client.flush();
                      client.stop();

                      return response;
                } // close flash.begin()

                if(!(INTERNAL_STORAGE_CLASS.begin(&flash))){
                #else
                if(!(INTERNAL_STORAGE_CLASS.begin())){
                #endif
                      EMailSender::Response response;
                      response.code = F("500");
                      response.desc = F("Error on startup filesystem!");
                      response.status = false;
                      client.flush();
                      client.stop();

                      return response;
                } // Close INTERNAL_STORAGE_CLASS.begin

                spiffsActive = true;
                DEBUG_PRINTLN("SPIFFS BEGIN, ACTIVE");
            } // Close INTERNAL_STORAGE_CLASS.exists
#endif

            EMAIL_FILE myFile = INTERNAL_STORAGE_CLASS.open(attachments.fileDescriptor[i].url, EMAIL_FILE_READ);
              if(myFile) {

// DEBUG_PRINTLN(myFile.name()); if (attachments.fileDescriptor[i].encode64){ encode(&myFile, &client); }else{ while(myFile.available()) { clientCount = myFile.read(tBuf,64); DEBUG_PRINTLN(clientCount); client.write((byte*)tBuf,clientCount); } } myFile.close();

                client.println();
              } // Else myfile
              else {
                  EMailSender::Response response;
                  response.code = F("404");
                  response.desc = "Error opening attachments file "+attachments.fileDescriptor[i].url;
                  response.status = false;
                  client.flush();
                  client.stop();

                  return response;
              } // Close myfile

        } // Close storageType

endif

ifdef STORAGE_EXTERNAL_ENABLED

        if (attachments.fileDescriptor[i].storageType==EMAIL_STORAGE_TYPE_SD){

ifdef OPEN_CLOSE_SD

             DEBUG_PRINTLN(F("SD Check"));
             if (!EXTERNAL_STORAGE_CLASS.exists(attachments.fileDescriptor[i].url.c_str())){

if EXTERNAL_STORAGE == STORAGE_SD || EXTERNAL_STORAGE == STORAGE_SDFAT2

                if(!EXTERNAL_STORAGE_CLASS.begin(SD_CS_PIN)){
                      response.code = F("500");
                      response.desc = F("Error on startup SD filesystem!");
                      response.status = false;
                      client.flush();
                      client.stop();

                      return response;
                } // Close EXTERNAL_STORAGE_CLASS.begin

elif EXTERNAL_STORAGE == STORAGE_SPIFM

                Adafruit_FlashTransport_SPI flashTransport(SS, SPI); // Set CS and SPI interface
                Adafruit_SPIFlash flash(&flashTransport);

              if (!EXTERNAL_STORAGE_CLASS.begin(&flash)) {
                  response.code = F("500");
                  response.desc = F("Error on startup SDFAT2 filesystem!");
                  response.status = false;
                  client.flush();
                  client.stop();

                  return response;
              }

endif

                sdActive = true;
             } // Close EXTERNAL_STORAGE_CLASS.exists

endif

            DEBUG_PRINTLN(F("Open file: "));
        EMAIL_FILE_EX myFile = EXTERNAL_STORAGE_CLASS.open(attachments.fileDescriptor[i].url.c_str());

          if(myFile) {
              myFile.seek(0);
              DEBUG_PRINTLN(F("OK"));
              if (attachments.fileDescriptor[i].encode64){
                  DEBUG_PRINTLN(F("BASE 64"));
                  encode(&myFile, &client);
              }else{
                  DEBUG_PRINTLN(F("NORMAL"));
                while(myFile.available()) {
                    clientCount = myFile.read(tBuf,64);
                    client.write((byte*)tBuf,clientCount);
                }
              }
            myFile.close();

            client.println();
          } // Else myfile
          else {
              response.code = F("404");
              response.desc = "Error opening attachments file "+attachments.fileDescriptor[i].url;
              response.status = false;
              client.flush();
              client.stop();

              return response;
          } // Close myFile

        } // Close storageType==EMAIL_STORAGE_TYPE_SD

else

if (attachments.fileDescriptor[i].storageType==EMAIL_STORAGE_TYPE_SD){
    response.code = F("500");
    response.desc = F("EMAIL_STORAGE_TYPE_SD not enabled on EMailSenderKey.h");
    response.status = false;
      client.flush();
      client.stop();

    return response;
}

endif

  } // Close attachment cycle
  client.println();
  client.println(F("--frontier--"));

ifdef STORAGE_EXTERNAL_ENABLED

  #ifdef OPEN_CLOSE_SD
      if (sdActive){
          DEBUG_PRINTLN(F("SD end"));
    #ifndef ARDUINO_ESP8266_RELEASE_2_4_2
          EXTERNAL_STORAGE_CLASS.end();
    #endif
          DEBUG_PRINTLN(F("SD end 2"));
      }
#endif

endif

ifdef STORAGE_INTERNAL_ENABLED

#ifdef OPEN_CLOSE_INTERNAL
    #if INTERNAL_STORAGE != STORAGE_SPIFM
      if (spiffsActive){
          INTERNAL_STORAGE_CLASS.end();
          DEBUG_PRINTLN(F("SPIFFS END"));
      }
#endif

endif

endif

  } // Close attachement enable

endif

DEBUG_PRINTLN(F("Message end")); client.println(F("."));

response = awaitSMTPResponse(client, "250", "Sending message error"); if (!response.status) { client.flush(); client.stop(); return response; }

client.println(F("QUIT"));

response = awaitSMTPResponse(client, "221", "SMTP QUIT error"); if (!response.status) { client.flush(); client.stop(); return response; }

response.status = true; response.code = F("0"); response.desc = F("Message sent!");

client.flush(); client.stop();

return response; }

BenSeventy9 commented 2 years ago

Thank you. I also had something similar in mind.

BenSeventy9 commented 2 years ago

I simplified it a bit: if (this->useEHLO == true) { for (int i = 0; i<=6; i++) { response = awaitSMTPResponse(client, "250", "EHLO error", 2500); if (!response.status) { DEBUG_PRINTLN(response.desc); break; } } } Got it down to 5 seconds.

salasidis commented 2 years ago

Thanks – I guess the await function had a max timeout field – that’s neater.

How long before these make it on the official Arduino libraries

From: BenSeventy9 @.> Sent: July 2, 2022 12:03 To: xreef/EMailSender @.> Cc: rsalasidis @.>; Mention @.> Subject: Re: [xreef/EMailSender] Needs more than 40 seconds to send. Any ideas why? (Issue #26)

I simplified it a bit: if (this->useEHLO == true) { for (int i = 0; i<=6; i++) { response = awaitSMTPResponse(client, "250", "EHLO error", 2500); if (!response.status) { DEBUG_PRINTLN(response.desc); break; } } }

— Reply to this email directly, view it on GitHubhttps://github.com/xreef/EMailSender/issues/26#issuecomment-1172920672, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AK5VYZLNFVDQMUKYZ3W2RDDVSBR4PANCNFSM5ZMZRLZQ. You are receiving this because you were mentioned.Message ID: @.**@.>>

xreef commented 2 years ago

Hi all, I do some changes to "regulate" the size of the response reader. I hope to release it in the next week. Bye Renzo

xreef commented 2 years ago

Hi, try now, if you find some other bugs write here I try to fix it. Bye Renzo

BenSeventy9 commented 2 years ago

Hi, try now, if you find some other bugs write here I try to fix it. Bye Renzo

I think you made a little mistake. Should't it be like this? if (this->additionalResponseLineOnHELO > 0){ for (int i = 0; i<=this->additionalResponseLineOnHELO; i++) { response = awaitSMTPResponse(client, "250", "EHLO error", 2500); if (!response.status && response.code == F("1")) { response.desc = F("Timeout! Reduce the HELO response line!"); client.flush(); // needs to be inside here client.stop(); // needs to be inside here return response; // needs to be inside here } } } This works fine for me. But anyway thanks for implementing this.

xreef commented 2 years ago

Azz.. yes, there is a copy-paste error @BenSeventy9 . I release this evening the little fix. Thanks again Renzo

xreef commented 2 years ago

I hope It's the last fix. Bye Renzo