diff --git a/README.md b/README.md index a3c38dd..3a1a053 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Mail Client Arduino Library for ESP32 v 1.1.1 +# Mail Client Arduino Library for ESP32 v 1.1.2 This library allows ESP32 to send Email with/without attachment and receive Email with/without attachment download via SMTP and IMAP servers. @@ -23,13 +23,13 @@ This following devices were tested and work well. * Support Email sending with or without attachment via IMAP server. -* Working with SD card allows large file attachment supported. +* Working with SD card allows large file attachment supported or SPIFFS for small file. * Support Email reading via search and fetch modes (with or without attachment downloads). -* Support large attachment download via SD card. +* Support large attachment download via SD card or SPIFFS for small file. -* Message text and its header are able to download and save to SD card. +* Message text and its header are able to download and save to SD card or SPIFFS. * Support Email message fetch and search via IMAP command as in RFC 3501 (depending on IMAP server implementation). @@ -124,6 +124,7 @@ To set sender, use `smtpData.addRecipient` e.g. `smtpData.addRecipient("SOME_REC To add attachment, use `smtpData.addAttachData` e.g. `smtpData.addAttachData("test.png", "image/png", (uint8_t *)imageData, sizeof imageData);`. + When completed all required message data, sending Email `MailClient.sendMail(http, smtpData)`. @@ -482,6 +483,20 @@ void setFechUID(const String fetchUID); + +**Set storage type to save download attached file or messages.** + +param *`storageType`* - The storage type to save file, MailClientStorageType::SD or MailClientStorageType::SPIFFS + +```C++ +void setFileStorageType(uint8_t storageType); +``` + + + + + + **Enable/disable attachment download.** param *`download`* - Boolean flag to enable/disable attachment download. @@ -1522,6 +1537,19 @@ void removeAttachFile(const String &filePath); +**Set storage type for all attach files.** + +param *`storageType`* - The storage type to read attach file, MailClientStorageType::SD or MailClientStorageType::SPIFFS. + +```C++ +void setFileStorageType(uint8_t storageType); +``` + + + + + + **Remove specified attachment file.** param *`index`* - The index of the attachment file (count only file type attachment) to remove. diff --git a/examples/Receive_email/Receive_email.ino b/examples/Receive_email/Receive_email.ino index 034f2dc..a736985 100644 --- a/examples/Receive_email/Receive_email.ino +++ b/examples/Receive_email/Receive_email.ino @@ -136,6 +136,10 @@ void setup() //Set to get attachment downloading progress status. imapData.setDownloadReport(true); + //Set the storage types to save download attachments or messages (SD is default) + //imapData.setFileStorageType(MailClientStorageType::SPIFFS) + imapData.setFileStorageType(MailClientStorageType::SD); + MailClient.readMail(http, imapData); } diff --git a/examples/Send_email/Send_email.ino b/examples/Send_email/Send_email.ino index 6666b98..e85f334 100644 --- a/examples/Send_email/Send_email.ino +++ b/examples/Send_email/Send_email.ino @@ -62,7 +62,7 @@ void setup() Serial.println("Mounting SD Card..."); - if (SD.begin()) + if (SD.begin()) // MailClient.sdBegin(14,2,15,13) for TTGO T8 v1.7 or 1.8 { Serial.println("Preparing attach file..."); @@ -136,6 +136,11 @@ void setup() smtpData.addAttachFile("/binary_file.dat"); smtpData.addAttachFile("/text_file.txt"); + //Set the storage types to read the attach files (SD is default) + //smtpData.setFileStorageType(MailClientStorageType::SPIFFS); + smtpData.setFileStorageType(MailClientStorageType::SD); + + smtpData.setSendCallback(sendCallback); diff --git a/library.properties b/library.properties index 282639a..aab985e 100644 --- a/library.properties +++ b/library.properties @@ -1,6 +1,6 @@ name=ESP32 Mail Client -version=1.1.1 +version=1.1.2 author=Mobizt diff --git a/src/ESP32_MailClient.cpp b/src/ESP32_MailClient.cpp index e1496fb..4c7d1eb 100644 --- a/src/ESP32_MailClient.cpp +++ b/src/ESP32_MailClient.cpp @@ -1,7 +1,7 @@ /* - *Mail Client Arduino Library for ESP32, version 1.1.1 + *Mail Client Arduino Library for ESP32, version 1.1.2 * - * June 16, 2019 + * June 17, 2019 * * This library allows ESP32 to send Email with/without attachment and receive Email with/without attachment download through SMTP and IMAP servers. * @@ -58,6 +58,7 @@ struct ESP32_MailClient::IMAP_HEADER_TYPE static const uint8_t ACCEPT_LANG = 8; }; + bool ESP32_MailClient::readMail(HTTPClientESP32Ex &http, IMAPData &imapData) { @@ -205,6 +206,7 @@ bool ESP32_MailClient::readMail(HTTPClientESP32Ex &http, IMAPData &imapData) imapData._headerOnly = false; else imapData._headerOnly = true; + if (imapData._headerOnly) { @@ -360,6 +362,7 @@ bool ESP32_MailClient::readMail(HTTPClientESP32Ex &http, IMAPData &imapData) command += buf; } + client->println(command.c_str()); std::string().swap(command); @@ -604,14 +607,19 @@ bool ESP32_MailClient::readMail(HTTPClientESP32Ex &http, IMAPData &imapData) if (!_sdOk) { + if(imapData._storageType==MailClientStorageType::SD){ _sdOk = sdTest(); - delay(200); - } + delay(200); + if (_sdOk) + if (!SD.exists(imapData._savePath.c_str())) + createDirs(imapData._savePath); + }else if(imapData._storageType==MailClientStorageType::SPIFFS) + _sdOk =SPIFFS.begin(true); + + } + + } - if (_sdOk) - if (!SD.exists(imapData._savePath.c_str())) - createDirs(imapData._savePath); - } if (imapData._messageDataInfo[mailIndex].size() > 0) { @@ -733,9 +741,19 @@ bool ESP32_MailClient::readMail(HTTPClientESP32Ex &http, IMAPData &imapData) } } - if (_sdOk) + + if(imapData._storageType==MailClientStorageType::SD) + { + if (_sdOk) SD.end(); + }else if(imapData._storageType==MailClientStorageType::SPIFFS) + { + if (_sdOk) + SPIFFS.end(); + } + + _sdOk = false; } @@ -1105,7 +1123,7 @@ bool ESP32_MailClient::sendMail(HTTPClientESP32Ex &http, SMTPData &smtpData) if (waitSMTPResponse(http) != 250) { - _smtpStatus = SMTP_STATUS_SEND_HEADER_FAILED; + _smtpStatus = SMTP_STATUS_SEND_HEADER_SENDER_FAILED; if (smtpData._sendCallback) { cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr(); @@ -1145,7 +1163,7 @@ bool ESP32_MailClient::sendMail(HTTPClientESP32Ex &http, SMTPData &smtpData) if (waitSMTPResponse(http) != 250) { - _smtpStatus = SMTP_STATUS_SEND_HEADER_FAILED; + _smtpStatus = SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED; if (smtpData._sendCallback) { cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr(); @@ -1186,7 +1204,7 @@ bool ESP32_MailClient::sendMail(HTTPClientESP32Ex &http, SMTPData &smtpData) if (waitSMTPResponse(http) != 250) { - _smtpStatus = SMTP_STATUS_SEND_HEADER_FAILED; + _smtpStatus = SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED; if (smtpData._sendCallback) { cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr(); @@ -1208,7 +1226,7 @@ bool ESP32_MailClient::sendMail(HTTPClientESP32Ex &http, SMTPData &smtpData) if (waitSMTPResponse(http) != 250) { - _smtpStatus = SMTP_STATUS_SEND_HEADER_FAILED; + _smtpStatus = SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED; if (smtpData._sendCallback) { cbData._info = ESP32_MAIL_STR_53 + smtpErrorReasonStr(); @@ -1281,25 +1299,48 @@ bool ESP32_MailClient::sendMail(HTTPClientESP32Ex &http, SMTPData &smtpData) } else { - if (!_sdOk) + + + if (!_sdOk){ + if(smtpData._storageType==MailClientStorageType::SD) _sdOk = sdTest(); + else if(smtpData._storageType==MailClientStorageType::SPIFFS) + _sdOk = SPIFFS.begin(true); + } + + if (!_sdOk) continue; - if (SD.exists(smtpData._attach._filename[i].c_str())) - { - cbData._info = smtpData._attach._filename[i]; - cbData._success = false; - if (smtpData._sendCallback) + bool file_existed =false; + if(smtpData._storageType==MailClientStorageType::SD) + file_existed =SD.exists(smtpData._attach._filename[i].c_str()); + else if(smtpData._storageType==MailClientStorageType::SPIFFS) + file_existed =SPIFFS.exists(smtpData._attach._filename[i].c_str()); + + + if (file_existed) + { + cbData._info = smtpData._attach._filename[i]; + cbData._success = false; + if (smtpData._sendCallback) smtpData._sendCallback(cbData); - buf.clear(); - set_attachment_header(i, buf, smtpData._attach); - client->print(buf.c_str()); - send_base64_encode_file(client, smtpData._attach._filename[i].c_str()); - client->print(ESP32_MAIL_STR_34); - } + buf.clear(); + set_attachment_header(i, buf, smtpData._attach); + client->print(buf.c_str()); + + File file; + if(smtpData._storageType==MailClientStorageType::SD) + file =SD.open(smtpData._attach._filename[i].c_str(), FILE_READ); + else if(smtpData._storageType==MailClientStorageType::SPIFFS) + file =SPIFFS.open(smtpData._attach._filename[i].c_str(), FILE_READ); + + send_base64_encode_file(client, file); + client->print(ESP32_MAIL_STR_34); + } + } } @@ -1362,40 +1403,7 @@ bool ESP32_MailClient::sendMail(HTTPClientESP32Ex &http, SMTPData &smtpData) String ESP32_MailClient::smtpErrorReason() { - std::string res = ""; - switch (_smtpStatus) - { - case SMTP_STATUS_SERVER_CONNECT_FAILED: - res = ESP32_MAIL_STR_38; - break; - case SMTP_STATUS_SMTP_RESPONSE_FAILED: - res = ESP32_MAIL_STR_39; - break; - case SMTP_STATUS_IDENTIFICATION_FAILED: - res = ESP32_MAIL_STR_41; - break; - case SMTP_STATUS_AUTHEN_NOT_SUPPORT: - res = ESP32_MAIL_STR_42; - break; - case SMTP_STATUS_AUTHEN_FAILED: - res = ESP32_MAIL_STR_43; - break; - case SMTP_STATUS_USER_LOGIN_FAILED: - res = ESP32_MAIL_STR_44; - break; - case SMTP_STATUS_PASSWORD_LOGIN_FAILED: - res = ESP32_MAIL_STR_47; - break; - case SMTP_STATUS_SEND_HEADER_FAILED: - res = ESP32_MAIL_STR_48; - break; - case SMTP_STATUS_SEND_BODY_FAILED: - res = ESP32_MAIL_STR_49; - break; - default: - res = ""; - } - return res.c_str(); + return smtpErrorReasonStr().c_str(); } std::string ESP32_MailClient::smtpErrorReasonStr() @@ -1424,9 +1432,12 @@ std::string ESP32_MailClient::smtpErrorReasonStr() case SMTP_STATUS_PASSWORD_LOGIN_FAILED: res = ESP32_MAIL_STR_47; break; - case SMTP_STATUS_SEND_HEADER_FAILED: + case SMTP_STATUS_SEND_HEADER_SENDER_FAILED: res = ESP32_MAIL_STR_48; break; + case SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED: + res = ESP32_MAIL_STR_222; + break; case SMTP_STATUS_SEND_BODY_FAILED: res = ESP32_MAIL_STR_49; break; @@ -1595,6 +1606,7 @@ int ESP32_MailClient::waitSMTPResponse(HTTPClientESP32Ex &http) continue; c = (char)r; + lineBuf.append(1, c); if (lineBuf.find(ESP32_MAIL_STR_158) != std::string::npos || lineBuf.find(ESP32_MAIL_STR_159) != std::string::npos) @@ -1675,20 +1687,21 @@ bool ESP32_MailClient::waitIMAPResponse(HTTPClientESP32Ex &http, IMAPData &imapD { while (client->available() || !completeResp) { - yield(); - + int r = client->read(); if (r < 0) continue; c = (char)r; + if (payloadLength > 0 && !completeResp) charCount++; if (imapCommandType == IMAP_COMMAND_TYPE::SEARCH && lfCount == 0) { + delayMicroseconds(1); if (c == ' ') { if (msgNumBuf != ESP32_MAIL_STR_183 && msgNumBuf != ESP32_MAIL_STR_141 && imapData._msgNum.size() <= max) @@ -1737,8 +1750,16 @@ bool ESP32_MailClient::waitIMAPResponse(HTTPClientESP32Ex &http, IMAPData &imapD filepath = imapData._savePath; filepath += ESP32_MAIL_STR_202; - filepath += imapData._msgNum[mailIndex]; + char * midx = new char[50]; + memset(midx, 0, 50); + itoa(imapData._msgNum[mailIndex], midx, 10); + + filepath += midx; + + delete[] midx; + + if(imapData._storageType==MailClientStorageType::SD) if (!SD.exists(filepath.c_str())) createDirs(filepath); @@ -1760,7 +1781,10 @@ bool ESP32_MailClient::waitIMAPResponse(HTTPClientESP32Ex &http, IMAPData &imapD filepath += ESP32_MAIL_STR_164; } - file = SD.open(filepath.c_str(), FILE_WRITE); + if(imapData._storageType==MailClientStorageType::SD) + file = SD.open(filepath.c_str(), FILE_WRITE); + else if(imapData._storageType==MailClientStorageType::SPIFFS) + file = SPIFFS.open(filepath.c_str(), FILE_WRITE); } else { @@ -2331,8 +2355,17 @@ bool ESP32_MailClient::waitIMAPResponse(HTTPClientESP32Ex &http, IMAPData &imapD filepath.clear(); filepath += imapData._savePath; filepath += ESP32_MAIL_STR_202; - filepath += imapData._msgNum[mailIndex]; + + char * midx = new char[50]; + memset(midx, 0, 50); + itoa(imapData._msgNum[mailIndex], midx, 10); + + filepath += midx; + delete[] midx; + + + if(imapData._storageType==MailClientStorageType::SD) if (!SD.exists(filepath.c_str())) createDirs(filepath); @@ -2353,8 +2386,12 @@ bool ESP32_MailClient::waitIMAPResponse(HTTPClientESP32Ex &http, IMAPData &imapD else filepath += ESP32_MAIL_STR_164; } - + + if(imapData._storageType==MailClientStorageType::SD) file = SD.open(filepath.c_str(), FILE_WRITE); + else if(imapData._storageType==MailClientStorageType::SPIFFS) + file = SPIFFS.open(filepath.c_str(), FILE_WRITE); + } else { @@ -2392,24 +2429,38 @@ bool ESP32_MailClient::waitIMAPResponse(HTTPClientESP32Ex &http, IMAPData &imapD { imapData._messageDataInfo[mailIndex][messageDataIndex]._sdFileOpenWrite = true; - + + if (_sdOk) { + downloadReq = true; filepath.clear(); filepath += imapData._savePath; filepath += ESP32_MAIL_STR_202; - filepath += imapData._msgNum[mailIndex]; + char * midx = new char[50]; + memset(midx, 0, 50); + itoa(imapData._msgNum[mailIndex], midx, 10); + + filepath += midx; + + delete[] midx; + + if(imapData._storageType==MailClientStorageType::SD) if (!SD.exists(filepath.c_str())) createDirs(filepath); filepath += ESP32_MAIL_STR_202; filepath += imapData._messageDataInfo[mailIndex][messageDataIndex]._filename; + + if(imapData._storageType==MailClientStorageType::SD) file = SD.open(filepath.c_str(), FILE_WRITE); + else if(imapData._storageType==MailClientStorageType::SPIFFS) + file = SPIFFS.open(filepath.c_str(), FILE_WRITE); } else { @@ -2424,7 +2475,7 @@ bool ESP32_MailClient::waitIMAPResponse(HTTPClientESP32Ex &http, IMAPData &imapD if (_sdOk) { - + unsigned char *decoded = base64_decode_char((const unsigned char *)lineBuf.c_str(), lineBuf.length(), &outputLength); downloadedByte += outputLength; @@ -2435,6 +2486,10 @@ bool ESP32_MailClient::waitIMAPResponse(HTTPClientESP32Ex &http, IMAPData &imapD if (decoded) { file.write((const uint8_t *)decoded, outputLength); + + if(imapData._storageType==MailClientStorageType::SPIFFS) + delayMicroseconds(1); + else yield(); if (imapData._downloadReport) @@ -2561,8 +2616,11 @@ bool ESP32_MailClient::waitIMAPResponse(HTTPClientESP32Ex &http, IMAPData &imapD if (hpath != "") { - + + if(imapData._storageType==MailClientStorageType::SD) file = SD.open(hpath.c_str(), FILE_WRITE); + else if(imapData._storageType==MailClientStorageType::SPIFFS) + file = SPIFFS.open(hpath.c_str(), FILE_WRITE); file.print(ESP32_MAIL_STR_99); file.println(imapData._date[mailIndex].c_str()); @@ -2784,7 +2842,7 @@ std::string ESP32_MailClient::base64_encode_string(const unsigned char *src, siz *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; *pos++ = base64_table[in[2] & 0x3f]; in += 3; - yield(); + //yield(); } if (end - in) @@ -2847,7 +2905,7 @@ void ESP32_MailClient::send_base64_encode_data(WiFiClient *client, const unsigne } in += 3; - yield(); + //yield(); } if (byteAdd > 0) @@ -2877,11 +2935,9 @@ void ESP32_MailClient::send_base64_encode_data(WiFiClient *client, const unsigne delete[] buf; } -void ESP32_MailClient::send_base64_encode_file(WiFiClient *client, const char *filePath) +void ESP32_MailClient::send_base64_encode_file(WiFiClient *client, File file) { - File file = SD.open(filePath, "r"); - if (!file) return; @@ -2920,7 +2976,7 @@ void ESP32_MailClient::send_base64_encode_file(WiFiClient *client, const char *f } fbufIndex += 3; - yield(); + //yield(); } else { @@ -3036,6 +3092,11 @@ void IMAPData::setFechUID(const String fetchUID) std::string().swap(tmp); } +void IMAPData::setFileStorageType(uint8_t storageType) +{ + _storageType = storageType; +} + void IMAPData::setDownloadAttachment(bool download) { _downloadAttachment = download; @@ -3959,6 +4020,12 @@ void SMTPData::removeAttachFile(uint8_t index) } } +void SMTPData::setFileStorageType(uint8_t storageType) +{ + _storageType = storageType; + +} + void SMTPData::clearAttachData() { for (uint8_t i = 0; i < _attach.getCount(); i++) diff --git a/src/ESP32_MailClient.h b/src/ESP32_MailClient.h index 41eda01..6e223c2 100644 --- a/src/ESP32_MailClient.h +++ b/src/ESP32_MailClient.h @@ -1,7 +1,7 @@ /* - *Mail Client Arduino Library for ESP32, version 1.1.1 + *Mail Client Arduino Library for ESP32, version 1.1.2 * - * June 16, 2019 + * June 17, 2019 * * This library allows ESP32 to send Email with/without attachment and receive Email with/without attachment download through SMTP and IMAP servers. * @@ -38,6 +38,8 @@ #include #include "SD.h" #include "SPI.h" +#include "FS.h" +#include "SPIFFS.h" #include "RFC2047.h" #define FORMAT_SPIFFS_IF_FAILED true @@ -53,8 +55,9 @@ using namespace std; #define SMTP_STATUS_AUTHEN_FAILED 5 #define SMTP_STATUS_USER_LOGIN_FAILED 6 #define SMTP_STATUS_PASSWORD_LOGIN_FAILED 7 -#define SMTP_STATUS_SEND_HEADER_FAILED 8 -#define SMTP_STATUS_SEND_BODY_FAILED 9 +#define SMTP_STATUS_SEND_HEADER_SENDER_FAILED 8 +#define SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED 9 +#define SMTP_STATUS_SEND_BODY_FAILED 10 #define IMAP_STATUS_SERVER_CONNECT_FAILED 1 #define IMAP_STATUS_IMAP_RESPONSE_FAILED 2 @@ -79,6 +82,12 @@ class MessageData; typedef void (*sendStatusCallback)(SendStatus); typedef void (*readStatusCallback)(ReadStatus); +struct MailClientStorageType +{ + static const uint8_t SPIFFS = 0; + static const uint8_t SD = 1; +}; + static const char ESP32_MAIL_STR_1[] PROGMEM = "Content-Type: multipart/mixed; boundary=\""; static const char ESP32_MAIL_STR_2[] PROGMEM = "{BOUNDARY}"; static const char ESP32_MAIL_STR_3[] PROGMEM = "Mime-Version: 1.0\r\n"; @@ -300,6 +309,7 @@ static const char ESP32_MAIL_STR_218[] PROGMEM = "["; static const char ESP32_MAIL_STR_219[] PROGMEM = "]"; static const char ESP32_MAIL_STR_220[] PROGMEM = "MIME"; static const char ESP32_MAIL_STR_221[] PROGMEM = "connection lost"; +static const char ESP32_MAIL_STR_222[] PROGMEM = "set recipient failed"; __attribute__((used)) static bool compFunc(uint32_t i, uint32_t j) { @@ -394,7 +404,7 @@ class ESP32_MailClient unsigned char *base64_decode_char(const unsigned char *src, size_t len, size_t *out_len); std::string base64_encode_string(const unsigned char *src, size_t len); void send_base64_encode_data(WiFiClient *tcp, const unsigned char *src, size_t len); - void send_base64_encode_file(WiFiClient *tcp, const char *filePath); + void send_base64_encode_file(WiFiClient *tcp, File file); int waitSMTPResponse(HTTPClientESP32Ex &http); bool waitIMAPResponse(HTTPClientESP32Ex &http, IMAPData &imapData, ReadStatus &cbData, uint8_t imapCommandType = 0, int maxChar = 0, int mailIndex = -1, int messageDataIndex = -1, std ::string part = ""); void createDirs(std::string dirs); @@ -590,6 +600,15 @@ class IMAPData */ void setFechUID(const String fetchUID); + /* + + Set storage type to save download attached file or messages. + + @param storageType - The storage type to save file, MailClientStorageType::SD or MailClientStorageType::SPIFFS + + */ + void setFileStorageType(uint8_t storageType); + /* Enable/disable attachment download. @@ -1114,6 +1133,7 @@ class IMAPData size_t _totalMessage = 0; std::string _host = ""; uint16_t _port = 993; + uint8_t _storageType = 1; std::string _loginEmail = ""; std::string _loginPassword = ""; std::string _currentFolder = "INBOX"; @@ -1483,6 +1503,7 @@ class SMTPData */ uint8_t attachDataCount(); + /* @@ -1512,6 +1533,15 @@ class SMTPData */ void removeAttachFile(uint8_t index); + /* + + Set storage type for all attach files. + + @param storageType - The storage type to read attach file, MailClientStorageType::SD or MailClientStorageType::SPIFFS + + */ + void setFileStorageType(uint8_t storageType); + /* Clear all attachment data @@ -1567,6 +1597,7 @@ class SMTPData string _loginPassword = ""; string _host = ""; uint16_t _port = 0; + uint8_t _storageType = 1; string _fromName = ""; string _senderEmail = "";