It was working for the longest time, but has not been working again – likely for the past 2 weeks (Only noticed now)
When trying to run, I get the following outputs (Debug Print turned on, and some debug prints of my own)
EmailSendFrom=Test123@mydomain.com
Test123@mydomain.com
Server=exch6.mydomain.com
exch6.mydomain.com
Port=587
Send to Email=anyemail@adomain.com
anyemail@adomain.com
In email routine
ONLY ONE RECIPIENTmiltiple destination and attachments
Insecure client:0
exch6.mydomain.com
587
220 EXCH6.MYDOMAIN.COM Microsoft ESMTP MAIL Service ready at Wed, 4 Jan 2023 15:31:51 -0500
EHLO mischianti
501 5.5.4 Invalid domain name
Sending status:
0
250
Identification error (501 5.5.4 Invalid domain name)
Hi rs77can,
I think your email provider change something about EHLO message.
Try to contact your provider or check if there was some system updade.
Bye Renzo
I am using my own hosted exchange server, and have not changed anything (have not added any new cumulative updates etc).
I tried EHLO or HELO, and both don’t work, but both work if I execute them in a TELNET window. It seems from wireshark trace (I sent it to your info email) there is no appropriate response from EHLO or HELO when sent by the code, and the program just hangs there.
Did maybe something change in the dependency libraries?
Hi rs77can,
no, nothing in particular, but you can try downloading an older library (in the Arduino IDE you can select all the previous version) to check if something is different.
Bye Renzo
I have created a small test program that just outputs the data to exchange server, and this works. I am not checking for correct responses, just proceeding after the client.println, and getting a response when expected – just not analyzing it.
I have tested the same code with the delays removed, and other than beiung faster, it also works.
In my main code it is a multitasking envioronment, but I had tried to run between OSCritical enable/disable, and that had not made a difference.
Can you see anything you can suggest for me to try to resolve the issue. The actual library seems to hang after ehlo or helo commands, at which point I get the
I made the following changes to the code, and it worked. Most of the changes are adding DEBUG_PRINTLN.
I added some client.flush() after the connect, and helo command, but they didn’t fix it.
It was only when I changed the ‘helo mischianti’ to helo + this->smtp_server that it worked.
Although the telnet connection did not care what was placed after the helo (I could even just send a helo all by itself), the exchange server was demanding a valid domain for the arduino, possibly because it is not a domain member IP address ???
Any way, here is the file
/*
* EMail Sender Arduino, esp8266, stm32 and esp32 library to send email
*
* AUTHOR: Renzo Mischianti
* VERSION: 3.0.6
*
* http://mischianti.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Renzo Mischianti www.mischianti.org All right reserved.
*
* You may copy, alter and reuse this code in any way you like, but please leave
* reference to www.mischianti.org in your comments if you redistribute this code.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "EMailSender.h"
#include <stdio.h>
//#include <SPIFFS.h>
//#include <LittleFS.h>
//#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)) {
DEBUG_PRINTLN(F("In response - timeout"));
response.code = F("1");
response.desc = String(respDesc) + "! " + F("SMTP Response TIMEOUT!");
response.status = false;
return response;
}
}
DEBUG_PRINTLN(F("In response"));
_serverResponce = client.readStringUntil('\n');
DEBUG_PRINTLN(_serverResponce);
if (resp && _serverResponce.indexOf(resp) == -1){
DEBUG_PRINTLN(F("In response - bad resp"));
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)
{
#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);
#ifndef FORCE_DISABLE_SSL
#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
#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;
}
client.flush();
response = awaitSMTPResponse(client, "220", "Connection Error");
if (!response.status) {
DEBUG_PRINTLN("Error: in response status after connect");
client.flush();
client.stop();
return response;
}
if (this->additionalResponseLineOnConnection > 0){
for (int i = 0; i<=this->additionalResponseLineOnConnection; i++) {
response = awaitSMTPResponse(client, "220", "Connection response error ", 2500);
if (!response.status && response.code == F("1")) {
response.desc = F("Connection error! Reduce the HELO response line!");
client.flush();
client.stop();
return response;
}
}
}
String commandHELO = "HELO";
if (this->useEHLO == true) {
commandHELO = "EHLO";
}
String helo = commandHELO + " " + this->smtp_server;
DEBUG_PRINTLN(helo);
client.println(helo);
client.flush();
response = awaitSMTPResponse(client, "250", "Identification error");
if (!response.status) {
DEBUG_PRINTLN("Error: after HELO - in response status ");
client.flush();
client.stop();
return response;
}
// if (this->useEHLO == true) {
// for (int i = 0; i<=6; i++) awaitSMTPResponse(client);
// }
//
// for (int i = 0; i <= 6; i++) {
// response = awaitSMTPResponse(client, "250", "EHLO error", 2500);
// if (!response.status && response.code == F("1")) {
// DEBUG_PRINTLN(response.desc);
// break;
// }
// }
DEBUG_PRINTLN("Got to after send HELO");
if (this->useEHLO == true && this->additionalResponseLineOnHELO == 0) {
DEBUG_PRINTLN("In use EHLO");
this->additionalResponseLineOnHELO = DEFAULT_EHLO_RESPONSE_COUNT;
}
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")) {
DEBUG_PRINTLN("Error: after HELO - timeout");
response.desc = F("Timeout! Reduce the HELO response line!");
client.flush();
client.stop();
return response;
}
}
}
DEBUG_PRINTLN("Got to Use Auth");
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) + "</html>";
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"));
DEBUG_PRINT(F("Readed filename: "));
DEBUG_PRINTLN(attachments.fileDescriptor[i].filename);
DEBUG_PRINT(F("Check if exist: "));
//DEBUG_PRINTLN(INTERNAL_STORAGE_CLASS.exists(attachments.fileDescriptor[i].url.c_str()));
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())){
DEBUG_PRINTLN(F("Begin internal storage!"));
#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
} // Close storageType
#endif
DEBUG_PRINT(F("Try to open "));
DEBUG_PRINTLN(attachments.fileDescriptor[i].url);
EMAIL_FILE myFile = INTERNAL_STORAGE_CLASS.open(attachments.fileDescriptor[i].url, EMAIL_FILE_READ);
if(myFile) {
DEBUG_PRINT(F("Filename -> "));
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
#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;
}
Maintaining a repository (or site or forum) is a lot like tending to a garden - it requires constant care and attention to keep it thriving. If you're a skilled gardener (or coder!) and want to help keep our repository blooming, we'd love to have you on board! We're also looking for talented writers and forum moderators to help us grow our community. Interested in joining our team? Don't hesitate to reach out and let us know how you can contribute!
Are you a fan of electronics or programming? Share your knowledge with others, write a simple tutorial or how to make a great project Contact me: share_your_ideas@mischianti.org
The content displayed on this website is protected under a CC BY-NC-ND license. Visitors are prohibited from using, redistributing, or altering any content from this website for commercial purposes, including generating revenue through advertising. Any unauthorized use is a violation of the license terms and legal action may be taken against individuals or entities found to be in violation.
You must also provide the link to the source.
To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
Functional
Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes.The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.
To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
Functional
Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes.The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.