Tasmota/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_Client.h
s-hadinger c2f8821b2f
Sendmail upgraded to ESP-Mail-Client v3.4.9 from v1.2.0, using BearSSL instead of MbedTLS (#19460)
* `Sendmail` upgraded to ESP-Mail-Client v3.4.9 from v1.2.0, using BearSSL instead of MbedTLS

* Fix compilation on ESP8266

* Fix compilation

* fix compilation
2023-09-04 23:00:37 +02:00

2863 lines
98 KiB
C++

#ifndef ESP_MAIL_CLIENT_H
#define ESP_MAIL_CLIENT_H
#include "ESP_Mail_Client_Version.h"
#if !VALID_VERSION_CHECK(30409)
#error "Mixed versions compilation."
#endif
/**
* Mail Client Arduino Library for Arduino devices.
*
* Created August 28, 2023
*
* This library allows Espressif's ESP32, ESP8266, SAMD and RP2040 Pico devices to send and read Email through the SMTP and IMAP servers.
*
* The MIT License (MIT)
* Copyright (c) 2023 K. Suwatchai (Mobizt)
*
*
* 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 <Arduino.h>
#include "extras/RFC2047.h"
#include <time.h>
#include <ctype.h>
#include <algorithm>
#include <string>
#include <vector>
#if __has_include(<string.h>)
#include <string.h>
#endif
#if __has_include(<stdarg.h>)
#include <stdarg.h>
#endif
#include "ESP_Mail_FS.h"
#include "ESP_Mail_Const.h"
#include "extras/MB_Time.h"
#if defined(MB_ARDUINO_ESP) || defined(MB_ARDUINO_PICO)
#define ESP_MAIL_PRINTF ESP_MAIL_DEFAULT_DEBUG_PORT.printf
#else
#define ESP_MAIL_PRINTF MailClient.printf
#endif
#if defined(ESP32) || defined(ESP8266) || defined(MB_ARDUINO_PICO)
#define UPLOAD_CHUNKS_NUM 12
#if defined(ESP32)
#define ESP_MAIL_MIN_MEM 70000
#elif defined(ESP8266)
#define SD_CS_PIN 15
#define ESP_MAIL_MIN_MEM 8000
#elif defined(MB_ARDUINO_PICO)
#define ESP_MAIL_MIN_MEM 70000
#define SD_CS_PIN PIN_SPI1_SS
#endif
#else
#undef min
#undef max
#define ESP_MAIL_MIN_MEM 3000
#define UPLOAD_CHUNKS_NUM 5
#ifdef __arm__
// should use uinstd.h to define sbrk but Due causes a conflict
extern "C" char *sbrk(int incr);
#else // __ARM__
extern char *__brkval;
#endif // __arm__
#endif
#include "ESP_Mail_TCPClient.h"
using namespace mb_string;
class IMAPSession;
class SMTPSession;
class SMTP_Status;
class DownloadProgress;
class MessageData;
#if defined(ENABLE_IMAP)
class MessageList
{
public:
friend class IMAPSession;
MessageList(){};
~MessageList() { clear(); };
void add(int uid)
{
if (uid > 0)
_list.push_back(uid);
}
void clear() { _list.clear(); }
private:
_vectorImpl<int> _list;
};
/* The class that provides the info of selected or opened mailbox folder */
class SelectedFolderInfo
{
public:
friend class ESP_Mail_Client;
friend class IMAPSession;
SelectedFolderInfo(){};
~SelectedFolderInfo() { clear(); };
/* Get the flags count for this mailbox */
size_t flagCount(bool permanent = false) { return permanent ? _permanent_flags.size() : _flags.size(); };
/* Get the numbers of messages in this mailbox */
size_t msgCount() { return _msgCount; };
/* Get the numbers of messages in this mailbox that recent flag was set */
size_t recentCount() { return _recentCount; };
/* Get the order of message in number of message in this mailbox that reoved */
/**
* The IMAP_Polling_Status has the properties e.g. type, messageNum, and argument.
*
* The type property is the type of status e.g.imap_polling_status_type_undefined, imap_polling_status_type_new_message,
* imap_polling_status_type_remove_message, and imap_polling_status_type_fetch_message.
*
* The messageNum property is message number or order from the total number of message that added, fetched or deleted.
*
* The argument property is the argument of commands e.g. FETCH
*/
IMAP_Polling_Status pollingStatus() { return _polling_status; };
/* Get the The unique identifier (UID) validity value */
size_t uidValidity() { return _uidValidity; };
/* Get the predict next message UID */
size_t nextUID() { return _nextUID; };
/* Get the index of first unseen message */
size_t unseenIndex() { return _unseenMsgIndex; };
/* Get the highest modification sequence */
uint64_t highestModSeq() { return strtoull(_highestModSeq.c_str(), NULL, 10); };
/* Check for the modification sequence supports */
bool modSeqSupported() { return _highestModSeq.length() > 0 && !_nomodsec; };
/* Get the numbers of messages from search result based on the search criteria
*/
size_t searchCount() { return _searchCount; };
/* Get the numbers of messages to be stored in the ressult */
size_t availableMessages() { return _availableItems; };
/* Get the flag argument at the specified index */
String flag(size_t index, bool permanent = false)
{
size_t size = permanent ? _permanent_flags.size() : _flags.size();
if (index < size)
return permanent ? _permanent_flags[index].c_str() : _flags[index].c_str();
return "";
}
private:
void addFlag(const char *flag, bool permanent)
{
MB_String s = flag;
if (permanent)
_permanent_flags.push_back(s);
else
_flags.push_back(s);
};
void clear()
{
for (size_t i = 0; i < _flags.size(); i++)
_flags[i].clear();
_flags.clear();
for (size_t i = 0; i < _permanent_flags.size(); i++)
_permanent_flags[i].clear();
_permanent_flags.clear();
_msgCount = 0;
_polling_status.argument.clear();
_polling_status.messageNum = 0;
_polling_status.type = imap_polling_status_type_undefined;
_idleTimeMs = 0;
_searchCount = 0;
}
size_t _msgCount = 0;
size_t _recentCount = 0;
size_t _uidValidity = 0;
size_t _nextUID = 0;
size_t _unseenMsgIndex = 0;
MB_String _highestModSeq;
size_t _searchCount = 0;
size_t _availableItems = 0;
unsigned long _idleTimeMs = 0;
bool _folderChanged = false;
bool _floderChangedState = false;
bool _nomodsec = false;
IMAP_Polling_Status _polling_status;
_vectorImpl<MB_String> _flags;
_vectorImpl<MB_String> _permanent_flags;
};
/* The class that provides the list of FolderInfo e.g. name, attributes and
* delimiter */
class FoldersCollection
{
public:
friend class ESP_Mail_Client;
friend class IMAPSession;
FoldersCollection(){};
~FoldersCollection() { clear(); };
size_t size() { return _folders.size(); };
struct esp_mail_folder_info_item_t info(size_t index)
{
struct esp_mail_folder_info_item_t fd;
if (index < _folders.size())
{
fd.name = _folders[index].name.c_str();
fd.attributes = _folders[index].attributes.c_str();
fd.delimiter = _folders[index].delimiter.c_str();
}
return fd;
}
esp_mail_folder_info_t operator[](size_t index)
{
if (index < _folders.size())
return _folders[index];
return esp_mail_folder_info_t();
}
private:
void add(struct esp_mail_folder_info_t fd) { _folders.push_back(fd); };
void clear()
{
for (size_t i = 0; i < _folders.size(); i++)
{
_folders[i].name.clear();
_folders[i].attributes.clear();
_folders[i].delimiter.clear();
}
_folders.clear();
}
_vectorImpl<esp_mail_folder_info_t> _folders;
};
/* The class that provides the list of IMAP_Quota_Root_Info e.g. resource name, used and limit */
class IMAP_Quota_Roots_List
{
friend class IMAPSession;
public:
IMAP_Quota_Roots_List(){};
~IMAP_Quota_Roots_List() { clear(); };
size_t size() { return _quota_roots.size(); };
IMAP_Quota_Root_Info operator[](size_t index)
{
if (index < _quota_roots.size())
return _quota_roots[index];
return IMAP_Quota_Root_Info();
}
private:
_vectorImpl<IMAP_Quota_Root_Info> _quota_roots;
void add(IMAP_Quota_Root_Info v)
{
_quota_roots.push_back(v);
}
void clear()
{
_quota_roots.clear();
}
};
/* The class that provides the list of IMAP_Namespaces */
class IMAP_Namespaces
{
friend class IMAPSession;
public:
IMAP_Namespaces(){};
~IMAP_Namespaces() { clear(); };
size_t size() { return _ns_list.size(); };
IMAP_Namespace_Info operator[](size_t index)
{
if (index < _ns_list.size())
return _ns_list[index];
return IMAP_Namespace_Info();
}
private:
_vectorImpl<IMAP_Namespace_Info> _ns_list;
void add(IMAP_Namespace_Info v)
{
_ns_list.push_back(v);
}
void clear()
{
_ns_list.clear();
}
};
/* The class that provides the list of IMAP_Namespaces */
class IMAP_Rights_List
{
friend class IMAPSession;
public:
IMAP_Rights_List(){};
~IMAP_Rights_List() { clear(); };
size_t size() { return _rights_list.size(); };
IMAP_Rights_Info operator[](size_t index)
{
if (index < _rights_list.size())
return _rights_list[index];
return IMAP_Rights_Info();
}
private:
_vectorImpl<IMAP_Rights_Info> _rights_list;
void add(IMAP_Rights_Info v)
{
_rights_list.push_back(v);
}
void clear()
{
_rights_list.clear();
}
};
typedef struct esp_mail_imap_nanespace_list_t
{
IMAP_Namespaces personal_namespaces;
IMAP_Namespaces other_users_namespaces;
IMAP_Namespaces shared_namespaces;
} IMAP_Namespaces_List;
/* The class that provides the status of message feching and searching */
class IMAP_Status
{
public:
IMAP_Status();
~IMAP_Status();
const char *info();
bool success();
void empty();
friend class IMAPSession;
MB_String _info;
bool _success = false;
};
typedef void (*imapStatusCallback)(IMAP_Status);
typedef void (*imapResponseCallback)(IMAP_Response);
typedef void (*MIMEDataStreamCallback)(MIME_Data_Stream_Info);
typedef void (*imapCharacterDecodingCallback)(IMAP_Decoding_Info *);
#else
enum esp_mail_imap_read_capability_types
{
esp_mail_imap_read_capability_maxType
};
// Dummy class used in template functions (errorStatusCB).
class IMAPSession
{
public:
struct IMAP_Status
{
public:
const char *info() { return ""; };
bool success() { return false; };
void empty();
MB_String _info;
bool _success = false;
};
typedef void (*imapStatusCallback)(IMAP_Status);
MB_String errorReason() { return ""; }
bool _debug;
imapStatusCallback _statusCallback = nullptr;
void *_customCmdResCallback = nullptr;
esp_mail_session_type _sessionType = esp_mail_session_type_imap;
struct esp_mail_imap_response_status_t
{
int errorCode = 0;
MB_String tag;
MB_String text;
MB_String status;
bool completed = false;
};
esp_mail_imap_response_status_t _responseStatus;
IMAP_Status _cbData;
};
#endif
#if defined(ENABLE_SMTP)
/* The SMTP message class */
class SMTP_Message
{
public:
SMTP_Message()
{
text.content_type = "text/plain";
html.content_type = "text/html";
};
~SMTP_Message() { clear(); };
void resetAttachItem(SMTP_Attachment &att)
{
att.blob.size = 0;
att.blob.data = nullptr;
att.file.path.clear();
att.file.storage_type = esp_mail_file_storage_type_none;
att.descr.name.clear();
att.descr.filename.clear();
att.descr.transfer_encoding.clear();
att.descr.content_encoding.clear();
att.descr.mime.clear();
att.descr.content_id.clear();
att._int.att_type = esp_mail_att_type_none;
att._int.index = 0;
att._int.msg_uid = 0;
att._int.flash_blob = false;
att._int.xencoding = esp_mail_msg_xencoding_none;
att._int.parallel = false;
att._int.cid.clear();
}
void clear()
{
sender.name.clear();
sender.email.clear();
subject.clear();
text.charSet.clear();
text.content.clear();
text.content_type.clear();
text.embed.enable = false;
html.charSet.clear();
html.content.clear();
html.content_type.clear();
html.embed.enable = false;
response.reply_to.clear();
response.notify = esp_mail_smtp_notify::esp_mail_smtp_notify_never;
priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal;
for (size_t i = 0; i < _rcp.size(); i++)
{
_rcp[i].name.clear();
_rcp[i].email.clear();
}
for (size_t i = 0; i < _cc.size(); i++)
_cc[i].email.clear();
for (size_t i = 0; i < _bcc.size(); i++)
_bcc[i].email.clear();
for (size_t i = 0; i < _hdr.size(); i++)
_hdr[i].clear();
for (size_t i = 0; i < _att.size(); i++)
{
_att[i].descr.filename.clear();
_att[i].blob.data = nullptr;
_att[i].descr.mime.clear();
_att[i].descr.name.clear();
_att[i].blob.size = 0;
_att[i].descr.transfer_encoding.clear();
_att[i].file.path.clear();
_att[i].file.storage_type = esp_mail_file_storage_type_none;
}
for (size_t i = 0; i < _parallel.size(); i++)
{
_parallel[i].descr.filename.clear();
_parallel[i].blob.data = nullptr;
_parallel[i].descr.mime.clear();
_parallel[i].descr.name.clear();
_parallel[i].blob.size = 0;
_parallel[i].descr.transfer_encoding.clear();
_parallel[i].file.path.clear();
_parallel[i].file.storage_type = esp_mail_file_storage_type_none;
}
_rcp.clear();
_cc.clear();
_bcc.clear();
_hdr.clear();
_att.clear();
_parallel.clear();
}
/** Clear all the inline images
*/
void clearInlineimages()
{
for (int i = (int)_att.size() - 1; i >= 0; i--)
{
if (_att[i]._int.att_type == esp_mail_att_type_inline)
_att.erase(_att.begin() + i);
}
};
/* Clear all the attachments */
void clearAttachments()
{
for (int i = (int)_att.size() - 1; i >= 0; i--)
{
if (_att[i]._int.att_type == esp_mail_att_type_attachment)
_att.erase(_att.begin() + i);
}
for (int i = (int)_parallel.size() - 1; i >= 0; i--)
_parallel.erase(_parallel.begin() + i);
};
/** Clear all rfc822 message attachment
*/
void clearRFC822Messages()
{
for (int i = (int)_rfc822.size() - 1; i >= 0; i--)
{
_rfc822[i].clear();
_rfc822.erase(_rfc822.begin() + i);
}
};
/** Clear the primary recipient mailboxes
*/
void clearRecipients() { _rcp.clear(); };
/** Clear the Carbon-copy recipient mailboxes
*/
void clearCc() { _cc.clear(); };
/** Clear the Blind-carbon-copy recipient mailboxes
*/
void clearBcc() { _bcc.clear(); };
/** Clear the custom message headers
*/
void clearHeader() { _hdr.clear(); };
/** Add attachment to the message
*
* @param att The SMTP_Attachment data item
*/
void addAttachment(SMTP_Attachment &att)
{
att._int.att_type = esp_mail_att_type_attachment;
att._int.parallel = false;
att._int.flash_blob = true;
_att.push_back(att);
};
/** Add parallel attachment to the message
*
* @param att The SMTP_Attachment data item
*/
void addParallelAttachment(SMTP_Attachment &att)
{
att._int.att_type = esp_mail_att_type_attachment;
att._int.parallel = true;
att._int.flash_blob = true;
_parallel.push_back(att);
};
/** Add inline image to the message
*
* @param att The SMTP_Attachment data item
*/
void addInlineImage(SMTP_Attachment &att)
{
att._int.flash_blob = true;
att._int.parallel = false;
att._int.att_type = esp_mail_att_type_inline;
att._int.cid = random(2000, 4000);
_att.push_back(att);
};
/** Add rfc822 message to the message
*
* @param msg The RFC822_Message class object
*/
void addMessage(SMTP_Message &msg) { _rfc822.push_back(msg); }
/** Add the primary recipient mailbox to the message
*
* @param name The name of primary recipient
* @param email The Email address of primary recipient
*/
template <typename T1 = const char *, typename T2 = const char *>
void addRecipient(T1 name, T2 email)
{
struct esp_mail_address_info_t rcp;
rcp.name = toStringPtr(name);
rcp.email = toStringPtr(email);
_rcp.push_back(rcp);
};
/** Add Carbon-copy recipient mailbox
*
* @param email The Email address of the secondary recipient
*/
template <typename T = const char *>
void addCc(T email)
{
struct esp_mail_address_info_t cc;
cc.email = toStringPtr(email);
_cc.push_back(cc);
};
/** Add Blind-carbon-copy recipient mailbox
*
* @param email The Email address of the tertiary recipient
*/
template <typename T = const char *>
void addBcc(T email)
{
struct esp_mail_address_info_t bcc;
bcc.email = toStringPtr(email);
_bcc.push_back(bcc);
};
/** Add the custom header to the message
*
* @param hdr The header name and value
*/
template <typename T = const char *>
void addHeader(T hdr)
{
_hdr.push_back(MB_String().setPtr(toStringPtr(hdr)));
};
/* The message author config */
struct esp_mail_address_info_t author;
/* The message sender (agent or teansmitter) config */
struct esp_mail_address_info_t sender;
/* The topic of message */
MB_String subject;
/* The message type */
byte type = esp_mail_msg_type_none;
/* The PLAIN text message */
esp_mail_plain_body_t text;
/* The HTML text message */
esp_mail_html_body_t html;
/* The response config */
struct esp_mail_smtp_msg_response_t response;
/* The priority of the message */
esp_mail_smtp_priority priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal;
/* The enable options */
struct esp_mail_smtp_enable_option_t enable;
/* The message from config */
struct esp_mail_address_info_t from;
/* The message identifier */
MB_String messageID;
/* The keywords or phrases, separated by commas */
MB_String keywords;
/* The comments about message */
MB_String comments;
/* The date of message */
MB_String date;
/* The field that contains the parent's message ID of the message to which this one is a reply */
MB_String in_reply_to;
/* The field that contains the parent's references (if any) and followed by the parent's message ID (if any) of the message to which this one is a reply */
MB_String references;
/* The timestamp value to replace in text */
esp_mail_timestamp_value_t timestamp;
private:
friend class ESP_Mail_Client;
_vectorImpl<struct esp_mail_address_info_t> _rcp;
_vectorImpl<struct esp_mail_address_info_t> _cc;
_vectorImpl<struct esp_mail_address_info_t> _bcc;
_vectorImpl<MB_String> _hdr;
_vectorImpl<SMTP_Attachment> _att;
_vectorImpl<SMTP_Attachment> _parallel;
_vectorImpl<SMTP_Message> _rfc822;
};
class SMTP_Status
{
public:
friend class SMTPSession;
friend class ESP_Mail_Client;
SMTP_Status();
~SMTP_Status();
const char *info();
bool success();
void empty();
size_t completedCount();
size_t failedCount();
private:
MB_String _info;
bool _success = false;
size_t _sentSuccess = 0;
size_t _sentFailed = 0;
};
typedef void (*smtpStatusCallback)(SMTP_Status);
typedef void (*smtpResponseCallback)(SMTP_Response);
#endif
class ESP_Mail_Client
{
public:
ESP_Mail_Client()
{
mbfs = new MB_FS();
};
~ESP_Mail_Client()
{
if (mbfs)
delete mbfs;
mbfs = nullptr;
wifi.clearAP();
};
#if defined(ENABLE_SMTP)
/** Sending Email through the SMTP server
*
* @param smtp The pointer to SMTP session object which holds the data and the
* TCP client.
* @param msg The pointer to SMTP_Message class which contains the header,
* body, and attachments.
* @param closeSession The option to Close the SMTP session after sent.
* @return The boolean value indicates the success of operation.
*/
bool sendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession = true);
#endif
#if defined(ENABLE_SMTP) && defined(ENABLE_IMAP)
/** Append message to the mailbox
*
* @param imap The pointer to IMAP session object which holds the data and the
* TCP client.
* @param msg The pointer to SMTP_Message class which contains the header,
* body, and attachments.
* @param lastAppend The last message to append (optional). In case of MULTIAPPEND extension
* is supported, set this to false will append messages in single APPEND command.
* @param flags The flags to set to this message (optional).
* @param dateTime The date/time to set to this message (optional).
* @return The boolean value indicates the success of operation.
*/
template <typename T1 = const char *, typename T2 = const char *>
bool appendMessage(IMAPSession *imap, SMTP_Message *msg, bool lastAppend = true, T1 flags = "", T2 dateTime = "") { return mAppendMessage(imap, msg, lastAppend, toStringPtr(flags), toStringPtr(dateTime)); }
#endif
#if defined(ENABLE_IMAP)
/** Reading Email through IMAP server.
*
* @param imap The pointer to IMAP session object which holds the data and
the TCP client.
* @param closeSession The option to close the IMAP session after fetching or
searching the Email.
* @return The boolean value indicates the success of operation.
*/
bool readMail(IMAPSession *imap, bool closeSession = true);
/** Set the argument to the Flags for the specified message.
*
* @param imap The pointer to IMAP session object which holds the data and the
* TCP client.
* @param msgUID The UID of the message.
* @param flags The flag list to set.
* @param closeSession The option to close the IMAP session after set flag.
* @param silent The option to ignore the response.
* @param modsequence The int32_t option for UNCHANGESINCE conditional test.
* @return The boolean value indicates the success of operation.
*
* The modsequence value can be used only if IMAP server supports Conditional STORE extension
* and the selected mailbox supports modsequences.
*/
template <typename T = const char *>
bool setFlag(IMAPSession *imap, int msgUID, T flags, bool closeSession, bool silent = false, int32_t modsequence = -1) { return mSetFlag(imap, toStringPtr(msgUID), toStringPtr(flags), esp_mail_imap_store_flag_type_set, closeSession, silent, true, modsequence); }
/** Set the argument to the Flags for the specified message.
*
* @param imap The pointer to IMAP session object which holds the data and the
* TCP client.
* @param sequenceSet The sequence set string i.g., unique identifier (UID) or message sequence number or ranges of UID or sequence number.
* @param UID The option for sequenceSet whether it is UID or message sequence number.
* @param flags The flag list to set.
* @param closeSession The option to close the IMAP session after set flag.
* @param silent The option to ignore the response.
* @param modsequence The int32_t option for UNCHANGESINCE conditional test.
* @return The boolean value indicates the success of operation.
*
* The modsequence value can be used only if IMAP server supports Conditional STORE extension
* and the selected mailbox supports modsequences.
*/
template <typename T1 = const char *, typename T2 = const char *>
bool setFlag(IMAPSession *imap, T1 sequenceSet, bool UID, T2 flags, bool closeSession, bool silent = false, int32_t modsequence = -1) { return mSetFlag(imap, toStringPtr(sequenceSet), toStringPtr(flags), esp_mail_imap_store_flag_type_set, closeSession, silent, UID, modsequence); }
/** Add the argument to the Flags for the specified message.
*
* @param imap The pointer to IMAP session object which holds the data and the
* TCP client.
* @param msgUID The UID of the message.
* @param flags The flag list to add.
* @param closeSession The option to close the IMAP session after add flag.
* @param silent The option to ignore the response.
* @param modsequence The int32_t option for UNCHANGESINCE conditional test.
* @return The boolean value indicates the success of operation.
*
* The modsequence value can be used only if IMAP server supports Conditional STORE extension
* and the selected mailbox supports modsequences.
*/
template <typename T = const char *>
bool addFlag(IMAPSession *imap, int msgUID, T flags, bool closeSession, bool silent = false, int32_t modsequence = -1) { return mSetFlag(imap, toStringPtr(msgUID), toStringPtr(flags), esp_mail_imap_store_flag_type_add, closeSession, silent, true, modsequence); }
/** Add the argument to the Flags for the specified message.
*
* @param imap The pointer to IMAP session object which holds the data and the
* TCP client.
* @param sequenceSet The sequence set string i.g., unique identifier (UID) or message sequence number or ranges of UID or sequence number.
* @param UID The option for sequenceSet whether it is UID or message sequence number.
* @param flags The flag list to add.
* @param closeSession The option to close the IMAP session after set flag.
* @param silent The option to ignore the response.
* @param modsequence The int32_t option for UNCHANGESINCE conditional test.
* @return The boolean value indicates the success of operation.
*
* The modsequence value can be used only if IMAP server supports Conditional STORE extension
* and the selected mailbox supports modsequences.
*/
template <typename T1 = const char *, typename T2 = const char *>
bool addFlag(IMAPSession *imap, T1 sequenceSet, bool UID, T2 flags, bool closeSession, bool silent = false, int32_t modsequence = -1) { return mSetFlag(imap, toStringPtr(sequenceSet), toStringPtr(flags), esp_mail_imap_store_flag_type_add, closeSession, silent, UID, modsequence); }
/** Remove the argument from the Flags for the specified message.
*
* @param imap The pointer to IMAP session object which holds the data and the
* TCP client.
* @param msgUID The UID of the message that flags to be removed.
* @param flags The flag list to remove.
* @param closeSession The option to close the IMAP session after remove flag.
* @param silent The option to ignore the response.
* @param modsequence The int32_t option for UNCHANGESINCE conditional test.
* @return The boolean value indicates the success of operation.
*
* The modsequence value can be used only if IMAP server supports Conditional STORE extension
* and the selected mailbox supports modsequences.
*/
template <typename T = const char *>
bool removeFlag(IMAPSession *imap, int msgUID, T flags, bool closeSession, bool silent = false, int32_t modsequence = -1) { return mSetFlag(imap, toStringPtr(msgUID), toStringPtr(flags), esp_mail_imap_store_flag_type_remove, closeSession, silent, true, modsequence); }
/** Remove the argument from the Flags for the specified message.
*
* @param imap The pointer to IMAP session object which holds the data and the
* TCP client.
* @param sequenceSet The sequence set string i.g., unique identifier (UID) or message sequence number or ranges of UID or sequence number.
* @param UID The option for sequenceSet whether it is UID or message sequence number.
* @param flags The flag list to remove.
* @param closeSession The option to close the IMAP session after set flag.
* @param silent The option to ignore the response.
* @param modsequence The int32_t option for UNCHANGESINCE conditional test.
* @return The boolean value indicates the success of operation.
*
* The modsequence value can be used only if IMAP server supports Conditional STORE extension
* and the selected mailbox supports modsequences.
*/
template <typename T1 = const char *, typename T2 = const char *>
bool removeFlag(IMAPSession *imap, T1 sequenceSet, bool UID, T2 flags, bool closeSession, bool silent = false, int32_t modsequence = -1) { return mSetFlag(imap, toStringPtr(sequenceSet), toStringPtr(flags), esp_mail_imap_store_flag_type_remove, closeSession, silent, UID, modsequence); }
#endif
/** Reconnect WiFi or network if lost connection.
*
* @param reconnect The boolean to set/unset WiFi AP reconnection.
*/
void networkReconnect(bool reconnect);
/* Obsoleted */
void setUDPClient(void *client, float gmtOffset) {}
/** Clear all WiFi access points assigned.
*
*/
void clearAP();
/** Add WiFi access point for non-ESP device to resume WiFi connection.
*
* @param ssid The WiFi SSID.
* @param password The WiFi password.
*/
void addAP(const String &ssid, const String &password);
/**
* Formatted printing on debug port.
*
*/
void printf(const char *format, ...);
#if defined(MBFS_SD_FS) && defined(MBFS_CARD_TYPE_SD)
/** Initiate SD card with SPI port configuration.
*
* @param ss SPI Chip/Slave Select pin.
* @param sck SPI Clock pin.
* @param miso SPI MISO pin.
* @param mosi SPI MOSI pin.
* @param frequency The SPI frequency
* @return Boolean type status indicates the success of the operation.
*/
bool sdBegin(int8_t ss = -1, int8_t sck = -1, int8_t miso = -1, int8_t mosi = -1, uint32_t frequency = 4000000);
#if defined(ESP8266) || defined(MB_ARDUINO_PICO)
/** Initiate SD card with SD FS configurations (ESP8266 only).
*
* @param ss SPI Chip/Slave Select pin.
* @param sdFSConfig The pointer to SDFSConfig object (ESP8266 only).
* @return Boolean type status indicates the success of the operation.
*/
bool sdBegin(SDFSConfig *sdFSConfig);
#endif
#if defined(ESP32)
/** Initiate SD card with chip select and SPI configuration (ESP32 only).
*
* @param ss SPI Chip/Slave Select pin.
* @param spiConfig The pointer to SPIClass object for SPI configuartion.
* @param frequency The SPI frequency.
* @return Boolean type status indicates the success of the operation.
*/
bool sdBegin(int8_t ss, SPIClass *spiConfig = nullptr, uint32_t frequency = 4000000);
#endif
#if defined(MBFS_ESP32_SDFAT_ENABLED) || defined(MBFS_SDFAT_ENABLED)
/** Initiate SD card with SdFat SPI and pins configurations (with SdFat included only).
*
* @param sdFatSPIConfig The pointer to SdSpiConfig object for SdFat SPI configuration.
* @param ss SPI Chip/Slave Select pin.
* @param sck SPI Clock pin.
* @param miso SPI MISO pin.
* @param mosi SPI MOSI pin.
* @return Boolean type status indicates the success of the operation.
*/
bool sdBegin(SdSpiConfig *sdFatSPIConfig, int8_t ss = -1, int8_t sck = -1, int8_t miso = -1, int8_t mosi = -1);
/** Initiate SD card with SdFat SDIO configuration (with SdFat included only).
*
* @param sdFatSDIOConfig The pointer to SdioConfig object for SdFat SDIO configuration.
* @return Boolean type status indicates the success of the operation.
*/
bool sdBegin(SdioConfig *sdFatSDIOConfig);
#endif
#endif
#if defined(ESP32) && defined(MBFS_SD_FS) && defined(MBFS_CARD_TYPE_SD_MMC)
/** Initialize the SD_MMC card (ESP32 only).
*
* @param mountpoint The mounting point.
* @param mode1bit Allow 1 bit data line (SPI mode).
* @param format_if_mount_failed Format SD_MMC card if mount failed.
* @return The boolean value indicates the success of operation.
*/
bool sdMMCBegin(const char *mountpoint = "/sdcard", bool mode1bit = false, bool format_if_mount_failed = false);
#endif
/** Get free Heap memory.
*
* @return Free memory amount in byte.
*/
int getFreeHeap();
/** Get base64 encode string.
*
* @return String of base64 encoded string.
*/
template <typename T = const char *>
String toBase64(T str) { return mGetBase64(toStringPtr(str)).c_str(); }
MB_Time Time;
#if defined(ENABLE_IMAP)
// Get encoding type from character set string
esp_mail_char_decoding_scheme getEncodingFromCharset(const char *enc);
// Decode Latin1 to UTF-8
int decodeLatin1_UTF8(unsigned char *out, int *outlen, const unsigned char *in, int *inlen);
// Decode TIS620 to UTF-8
void decodeTIS620_UTF8(char *out, const char *in, size_t len);
// handle rfc2047 Q (quoted printable) and B (base64) decodings
RFC2047_Decoder RFC2047Decoder;
#endif
private:
friend class SMTPSession;
friend class IMAPSession;
MB_FS *mbfs = nullptr;
bool timeStatus = false;
time_t ts = 0;
bool networkAutoReconnect = true;
volatile bool networkStatus = false;
esp_mail_wifi_credentials_t wifi;
bool timezoneEnvSet = false;
IMAPSession *imap = nullptr;
bool calDataLen = false;
uint32_t dataLen = 0;
uint32_t imap_ts = 0;
#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP)
unsigned long _lastReconnectMillis = 0;
uint16_t _reconnectTimeout = ESP_MAIL_NETWORK_RECONNECT_TIMEOUT;
// Resume network connection
void resumeNetwork(ESP_Mail_TCPClient *client);
// Get the CRLF ending string w/wo CRLF included. Return the size of string read and the current octet read.
int readLine(ESP_Mail_TCPClient *client, char *buf, int bufLen, bool withLineBreak, int &count, bool &ovf, unsigned long timeoutSec, bool &isTimeout);
// readLine with overflow handling.
template <class T>
bool readResponse(T sessionPtr, char *buf, int bufLen, int &readLen, bool withLineBreak, int &count, MB_String &ovfBuf);
// Network reconnection and return the connection status
template <class T>
bool reconnect(T sessionPtr, unsigned long dataTime = 0, bool downloadRequest = false);
// Send callback
template <class T>
void sendCB(T sessionPtr, PGM_P info = "", bool prependCRLF = false, bool success = false);
// PGM string replacement
void strReplaceP(MB_String &buf, PGM_P key, PGM_P value);
// Check for OAuth log in error response
bool isOAuthError(char *buf, int bufLen, int &chunkIdx, int ofs);
// Get SASL XOAUTH2 string
MB_String getXOAUTH2String(const MB_String &email, const MB_String &accessToken);
// Send error callback
template <class T>
void sendErrorCB(T sessionPtr, PGM_P info, bool prependCRLF = false, bool success = false);
// Send the error status callback
template <class T1, class T2>
void errorStatusCB(T1 sessionPtr, T2 sessionPtr2, int error, bool clearLastStatus);
// Check response callback was assigned?
template <class T>
bool isResponseCB(T sessionPtr);
// Print library info
template <class T>
void printLibInfo(T sessionPtr);
// Begin server connection
template <class T>
bool beginConnection(Session_Config *session_config, T sessionPtr, bool secureMode);
// Prepare system time
template <class T>
bool prepareTime(Session_Config *session_config, T sessionPtr);
// Check for session. Close session If not ready.
template <class T>
bool sessionReady(T sessionPtr);
// Set cert data
void setCert(Session_Config *session_cfg, const char *ca);
// Set secure data
void setSecure(ESP_Mail_TCPClient &client, Session_Config *session_config);
void appendMultipartContentType(MB_String &buf, esp_mail_multipart_types type, const char *boundary);
String errorReason(bool isSMTP, int errorCode, const char *msg);
// Close TCP session and clear auth_capability, read/send_capability, connected and authenticate statuses
template <class T>
void closeTCPSession(T sessionPtr);
// Get and set timezone
void getSetTimezoneEnv(const char *TZ_file, const char *TZ_Var);
// Get TCP connected status
template <class T>
bool connected(T sessionPtr);
// Get the memory allocation block size of multiple of 4
size_t getReservedLen(size_t len);
// Check Email for valid format
bool validEmail(const char *s);
// Get random UID for SMTP content ID and IMAP attachment default file name
char *getRandomUID();
// Spit the string into token strings
void splitToken(const char *str, _vectorImpl<MB_String> &tk, const char *delim);
// Decode base64 encoded string
unsigned char *decodeBase64(const unsigned char *src, size_t len, size_t *out_len);
// Decode base64 encoded string
MB_String encodeBase64Str(const unsigned char *src, size_t len);
// Decode base64 encoded string
MB_String encodeBase64Str(uint8_t *src, size_t len);
// Decode base64 encoded string
MB_String mGetBase64(MB_StringPtr str);
// Sub string
char *subStr(const char *buf, PGM_P beginToken, PGM_P endToken, int beginPos, int endPos = 0, bool caseSensitive = true);
// Find string
int strpos(const char *haystack, const char *needle, int offset, bool caseSensitive = true);
// Memory allocation
template <typename T>
T allocMem(size_t size, bool clear = true);
// Memory deallocation
void freeMem(void *ptr);
// PGM string compare
bool strcmpP(const char *buf, int ofs, PGM_P beginToken, bool caseSensitive = true);
// Find PGM string
int strposP(const char *buf, PGM_P beginToken, int ofs, bool caseSensitive = true);
// Memory allocation for PGM string
char *strP(PGM_P pgm);
// Memory allocation for PGM lower case string
char *strP2Lower(PGM_P pgm);
// Set or sync device system time with NTP server
// Do not modify or remove
void setTime(const char *TZ_Var, const char *TZ_file, bool wait, bool debugProgress);
// Set the device time zone via TZ environment variable
void setTimezone(const char *TZ_Var, const char *TZ_file);
// Get TZ environment variable from file
// Do not modify or remove
void getTimezone(const char *TZ_file, MB_String &out);
// Check the session existent
template <class T>
bool sessionExisted(T sessionPtr);
// Send SMTP/IMAP callback
template <class T>
void sendCallback(T sessionPtr, PGM_P info, bool prependCRLF, bool success);
// Send IMAP/SMTP response callback and print debug message
template <class T>
void printDebug(T sessionPtr, PGM_P cbMsg, PGM_P dbMsg, esp_mail_debug_tag_type type, bool prependCRLF, bool success);
// Get header content from response based on the field name
bool getHeader(const char *buf, PGM_P beginToken, MB_String &out, bool caseSensitive);
// Append header field to buffer
void appendHeaderField(MB_String &buf, const char *name, PGM_P value, bool comma, bool newLine, esp_mail_string_mark_type type = esp_mail_string_mark_type_none);
// Append SMTP address header field
void appendAddressHeaderField(MB_String &buf, esp_mail_address_info_t &source, esp_mail_rfc822_header_field_types type, bool header, bool comma, bool newLine);
// Append header field name to buffer
void appendHeaderName(MB_String &buf, const char *name, bool clear = false, bool lowercase = false, bool space = true);
// Append lowercase string to buffer
void appendLowerCaseString(MB_String &buf, PGM_P value, bool clear = false);
// Append header field property to buffer
void appendHeaderProp(MB_String &buf, PGM_P prop, const char *value, bool &firstProp, bool lowerCase, bool isString, bool newLine);
// Append quote string to buffer
void appendString(MB_String &buf, PGM_P value, bool comma, bool newLine, esp_mail_string_mark_type type = esp_mail_string_mark_type_none);
// Append list to buffer
template <class T>
void appendList(MB_String &buf, _vectorImpl<T> &list);
// Append space to buffer
void appendSpace(MB_String &buf);
// Append space to buffer after value
void appendSpace(MB_String &buf, bool withTag, PGM_P value);
// Append space to buffer after values
void appendSpace(MB_String &buf, bool withTag, int nunArgs, ...);
// Append space to buffer before value
void prependSpace(MB_String &buf, PGM_P value);
// Append dot to buffer
void appendDot(MB_String &buf);
// Append IMAP string key value list
void appendImap4KeyValue(MB_String &buf, PGM_P key, PGM_P value);
// Append dot to buffer before value
void prependDot(MB_String &buf, PGM_P value);
// Join 2 strings to buffer with space
void joinStringSpace(MB_String &buf, bool withTag, int nunArgs, ...);
// Join 2 strings to buffer with dot
void joinStringDot(MB_String &buf, int nunArgs, ...);
// Append mask(*) string to buffer
void maskString(MB_String &buf, int len);
// Append domain to buffer
void appendDomain(MB_String &buf, const char *domain);
// Append embedded message header to buffer
void appendEmbedMessage(MB_String &buf, esp_mail_message_body_t &body, bool isHtml);
// Append crlf to buffer
void appendNewline(MB_String &buf);
// Append tag to the buffer
void appendTagSpace(MB_String &buf, PGM_P tag = NULL);
// Print newline
void debugPrintNewLine();
// Send newline to callback
template <class T>
void callBackSendNewLine(T sessionPtr, bool success);
// Print progress bar
void printProgress(int progress, int &lastProgress);
// Get file extension with dot from MIME string
void getExtfromMIME(const char *mime, MB_String &ext);
// Prepare ports
void preparePortFunction(Session_Config *session_config, bool isSMTP, bool &secure, bool &secureMode, bool &ssl);
// Get operation config based on port and its protocol
void getPortFunction(uint16_t port, struct esp_mail_ports_functions &ports_functions, bool &secure, bool &secureMode, bool &ssl, bool &starttls);
#endif
#if defined(ENABLE_SMTP)
// Encode Quoted Printable string
void encodeQP(const char *buf, char *out);
// Add the soft line break to the long text line rfc 3676
void formatFlowedText(MB_String &content);
// Insert soft break
void softBreak(MB_String &content, const char *quoteMarks);
// Get content type (MIME) from file extension
void getMIME(const char *ext, MB_String &mime);
// Get content type (MIME) from file name
void mimeFromFile(const char *name, MB_String &mime);
// Get MIME boundary string
MB_String getMIMEBoundary(size_t len);
// Send Email function
bool mSendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession = true);
// SMTP send data
size_t smtpSend(SMTPSession *smtp, PGM_P data, bool newline = false);
// SMTP send data
size_t smtpSend(SMTPSession *smtp, int data, bool newline = false);
// SMTP send data
size_t smtpSend(SMTPSession *smtp, uint8_t *data, size_t size);
// Handle the error by sending callback and close session
bool handleSMTPError(SMTPSession *smtp, int err, bool ret = false);
// Send parallel attachment RFC1521
bool sendParallelAttachments(SMTPSession *smtp, SMTP_Message *msg, const MB_String &boundary);
// Send attachment
bool sendAttachments(SMTPSession *smtp, SMTP_Message *msg, const MB_String &boundary, bool parallel = false);
// Send message content
bool sendContent(SMTPSession *smtp, SMTP_Message *msg, bool closeSession, bool rfc822MSG);
// Send imap or smtp callback
void altSendCallback(SMTPSession *smtp, PGM_P cbMsg, PGM_P dbMsg, esp_mail_debug_tag_type type, bool prependCRLF, bool success);
// Send message data
bool sendMSGData(SMTPSession *smtp, SMTP_Message *msg, bool closeSession, bool rfc822MSG);
// Send RFC 822 message
bool sendRFC822Msg(SMTPSession *smtp, SMTP_Message *msg, const MB_String &boundary, bool closeSession, bool rfc822MSG);
// Get RFC 822 message envelope
void getRFC822MsgEnvelope(SMTPSession *smtp, SMTP_Message *msg, MB_String &buf);
// Append boundary string to buffer
void appendBoundaryString(MB_String &buf, const char *value, bool endMark, bool newLine);
// Send BDAT command RFC 3030
bool sendBDAT(SMTPSession *smtp, SMTP_Message *msg, int len, bool last);
// Get transfer encoding
void getXEncoding(esp_mail_msg_xencoding &xencoding, const char *enc);
// Set the unencoded xencoding enum for html, text and attachment from its xencoding string
void checkUnencodedData(SMTPSession *smtp, SMTP_Message *msg);
// Check imap or smtp has callback set
bool altIsCB(SMTPSession *smtp);
// Check imap or smtp has debug set
bool altIsDebug(SMTPSession *smtp);
// Send BLOB attachment
bool sendBlobAttachment(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att);
// Send file content
bool sendFile(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att);
// Send imap or smtp storage error callback
void altSendStorageErrorCB(SMTPSession *smtp, int err);
// Open file to send an attachment
bool openFileRead(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att, MB_String &buf, const MB_String &boundary, bool inlined);
// Open text file or html file for to send message
bool openFileRead2(SMTPSession *smtp, SMTP_Message *msg, const char *path, esp_mail_file_storage_type storageType);
// Send inline attachments
bool sendInline(SMTPSession *smtp, SMTP_Message *msg, const MB_String &boundary, byte type);
// Send storage error callback
void sendStorageNotReadyError(SMTPSession *smtp, esp_mail_file_storage_type storageType);
// Append message
bool mAppendMessage(IMAPSession *imap, SMTP_Message *msg, bool lastAppend, MB_StringPtr flags, MB_StringPtr dateTime);
// Get numbers of attachment based on type
size_t numAtt(SMTPSession *smtp, esp_mail_attach_type type, SMTP_Message *msg);
// Check for valid recipient Email
bool checkEmail(SMTPSession *smtp, SMTP_Message *msg);
// Send text parts MIME message
bool sendPartText(SMTPSession *smtp, SMTP_Message *msg, byte type, const char *boundary);
// Alternative string data sending to send imap APPEND data or smtp data
bool altSendData(MB_String &s, bool newLine, SMTPSession *smtp, SMTP_Message *msg, bool addSendResult, bool getResponse, esp_mail_smtp_command cmd, esp_mail_smtp_status_code statusCode, int errCode);
// Alternative bytes data sending to send imap APPEND data or smtp data
bool altSendData(uint8_t *data, size_t size, SMTPSession *smtp, SMTP_Message *msg, bool addSendResult, bool getResponse, esp_mail_smtp_command cmd, esp_mail_smtp_status_code statusCode, int errCode);
// Send MIME message
bool sendMSG(SMTPSession *smtp, SMTP_Message *msg, const MB_String &boundary);
// Get an attachment part header string
void getAttachHeader(MB_String &header, const MB_String &boundary, SMTP_Attachment *attach, size_t size, bool isInline);
// Get RFC 8222 part header string
void getRFC822PartHeader(SMTPSession *smtp, MB_String &header, const MB_String &boundary);
// Send BLOB type text part or html part MIME message
bool sendBlobBody(SMTPSession *smtp, SMTP_Message *msg, uint8_t type);
// Send file type text part or html part MIME message
bool sendFileBody(SMTPSession *smtp, SMTP_Message *msg, uint8_t type);
// Base64 and QP encodings for text and html messages and replace embeded attachment file name with content ID
void encodingText(SMTPSession *smtp, SMTP_Message *msg, uint8_t type, MB_String &content);
// Blob or Stream available
int chunkAvailable(SMTPSession *smtp, esp_mail_smtp_send_base64_data_info_t &data_info);
// Read chunk data of blob or file
int getChunk(SMTPSession *smtp, esp_mail_smtp_send_base64_data_info_t &data_info, unsigned char *rawChunk, bool base64);
// Terminate chunk reading
void closeChunk(esp_mail_smtp_send_base64_data_info_t &data_info);
// Get base64 encoded buffer or raw buffer
void getBuffer(bool base64, uint8_t *out, uint8_t *in, int &encodedCount, int &bufIndex, bool &dataReady, int &size, size_t chunkSize);
// Send blob or file as base64 encoded chunk
bool sendBase64(SMTPSession *smtp, SMTP_Message *msg, esp_mail_smtp_send_base64_data_info_t &data_info, bool base64, bool report);
// Save sending logs to file
void saveSendingLogs(SMTPSession *smtp, SMTP_Message *msg, bool result);
// Get imap or smtp report progress var pointer
uint32_t altProgressPtr(SMTPSession *smtp);
// Get SMTP response status (statusCode and text)
void getResponseStatus(const char *buf, esp_mail_smtp_status_code statusCode, int beginPos, struct esp_mail_smtp_response_status_t &status);
// Parse SMTP authentication capability
void parseAuthCapability(SMTPSession *smtp, char *buf);
// Add the sending result
bool addSendingResult(SMTPSession *smtp, SMTP_Message *msg, bool result, bool showResult);
// Handle SMTP server authentication
bool smtpAuth(SMTPSession *smtp, bool &ssl);
// Handle SMTP response
bool handleSMTPResponse(SMTPSession *smtp, esp_mail_smtp_command cmd, esp_mail_smtp_status_code statusCode, int errCode);
// Print the upload status to the debug port
void uploadReport(const char *filename, uint32_t pgAddr, int progress);
// Get MB_FS object pointer
MB_FS *getMBFS();
// Set device system time
int setTimestamp(time_t ts);
#endif
#if defined(ENABLE_IMAP)
// Check if child part (part number string) is a member of the parent part (part number string)
// part number string format: <part number>.<sub part number>.<sub part number>
bool multipartMember(const MB_String &parent, const MB_String &child);
// Decode string
int decodeChar(const char *s);
// Decode Quoted Printable string
void decodeQP_UTF8(const char *buf, char *out);
// Actually not decode because 7bit string is enencode string unless prepare valid 7bit string and do qp decoding
char *decode7Bit_UTF8(char *buf);
// Actually not decode because 8bit string is enencode string unless prepare valid 8bit string
char *decode8Bit_UTF8(char *buf);
// Decode string base on encoding
void decodeString(IMAPSession *imap, MB_String &string, const char *enc = "");
/**
* Encode a code point using UTF-8
*
* @author Ondřej Hruška <ondra@ondrovo.com>
* https://gist.github.com/MightyPork/52eda3e5677b4b03524e40c9f0ab1da5
*
* @license MIT
*
* @param out - output buffer (min 5 characters), will be 0-terminated
* @param utf - code point 0-0x10FFFF
* @return number of bytes on success, 0 on failure (also produces U+FFFD, which uses 3 bytes)
*/
int encodeUnicode_UTF8(char *out, uint32_t utf);
// Append headers fetch command
void appendHeadersFetchCommand(IMAPSession *imap, MB_String &cmd, int index, bool debug);
// Append rfc822 headers fetch command
void appendRFC822HeadersFetchCommand(MB_String &cmd);
// Get multipart MIME fetch command
bool getMultipartFechCmd(IMAPSession *imap, int msgIdx, MB_String &partText);
// Fetch multipart MIME body header
bool fetchMultipartBodyHeader(IMAPSession *imap, int msgIdx);
// Print body part fetching debug
void printBodyPartFechingDubug(IMAPSession *imap, const char *partNum, bool multiLevel);
// Handle IMAP server authentication
bool imapAuth(IMAPSession *imap, bool &ssl);
// Send IMAP command
bool sendFetchCommand(IMAPSession *imap, int msgIndex, esp_mail_imap_command cmdCase);
// Send data
size_t imapSend(IMAPSession *imap, PGM_P data, bool newline = false);
// Send data
size_t imapSend(IMAPSession *imap, int data, bool newline = false);
// Send data
size_t imapSend(IMAPSession *imap, uint8_t *data, size_t size);
// Log out
bool imapLogout(IMAPSession *imap);
// Send storage error callback
void sendStorageNotReadyError(IMAPSession *imap, esp_mail_file_storage_type storageType);
// Parse search response
int parseSearchResponse(IMAPSession *imap, esp_mail_imap_response_data &res, PGM_P tag, const char *key);
// Parse header state
bool parseHeaderField(IMAPSession *imap, const char *buf, PGM_P beginToken, bool caseSensitive, struct esp_mail_message_header_t &header, int &headerState, int state);
// Parse header response
void parseHeaderResponse(IMAPSession *imap, esp_mail_imap_response_data &res, bool caseSensitive = true);
// Set the header based on state parsed
void collectHeaderField(IMAPSession *imap, char *buf, struct esp_mail_message_header_t &header, int state);
// Get decoded header
bool getDecodedHeader(IMAPSession *imap, const char *buf, PGM_P beginToken, MB_String &out, bool caseSensitive);
// Check attachment for firmware file
void checkFirmwareFile(IMAPSession *imap, const char *filename, struct esp_mail_message_part_info_t &part, bool defaultSize = false);
// Parse part header response
void parsePartHeaderResponse(IMAPSession *imap, esp_mail_imap_response_data &res, bool caseSensitive = true);
// Count char in string
int countChar(const char *buf, char find);
// Store the value to string via its the pointer
bool storeStringPtr(IMAPSession *imap, uint32_t addr, MB_String &value, const char *buf);
// Get part header properties
bool getPartHeaderProperties(IMAPSession *imap, const char *buf, PGM_P p, PGM_P e, bool num, MB_String &value, MB_String &old_value, esp_mail_char_decoding_scheme &scheme, bool caseSensitive);
// Url decode for UTF-8 encoded header text
char *urlDecode(const char *str);
// Reset the pointer to multiline response keeping string
void resetStringPtr(struct esp_mail_message_part_info_t &part);
// Get current part
struct esp_mail_message_part_info_t *cPart(IMAPSession *imap);
// Get current header
struct esp_mail_message_header_t *cHeader(IMAPSession *imap);
#if !defined(MB_USE_STD_VECTOR)
// Decending sort
void numDecSort(_vectorImpl<struct esp_mail_imap_msg_num_t> &arr);
#endif
// Handle IMAP response
bool handleIMAPResponse(IMAPSession *imap, int errCode, bool closeSession);
// Print the file download status via debug port
void downloadReport(IMAPSession *imap, int progress);
// Print the message fetch status via debug port
void fetchReport(IMAPSession *imap, int progress, bool html);
// Print the message search status via debug port
void searchReport(IMAPSession *imap, int progress);
// Get current message num item
struct esp_mail_imap_msg_num_t cMSG(IMAPSession *imap);
// Get current message Index
int cIdx(IMAPSession *imap);
// Get IMAP response status e.g. OK, NO and Bad status enum value
esp_mail_imap_response_status imapResponseStatus(IMAPSession *imap, char *response, PGM_P tag);
// Add header item to string buffer
void addHeaderItem(MB_String &str, esp_mail_message_header_t *header, bool json);
// Get RFC822 header string pointer by index
int getRFC822HeaderPtr(int index, esp_mail_imap_rfc822_msg_header_item_t *header);
// Add RFC822 headers to string buffer
void addRFC822Headers(MB_String &s, esp_mail_imap_rfc822_msg_header_item_t *header, bool json);
// Add RFC822 header item to string buffer
void addRFC822HeaderItem(MB_String &s, esp_mail_imap_rfc822_msg_header_item_t *header, int index, bool json);
// Add header string by name and value to string buffer
void addHeader(MB_String &s, const char *name, const char *s_value, int num_value, bool trim, bool isJson);
// Save header string buffer to file
void saveHeader(IMAPSession *imap, bool json);
// Send MIME stream to callback
void sendStreamCB(IMAPSession *imap, void *buf, size_t len, int chunkIndex, bool hrdBrk);
// Prepare file path for saving
void prepareFilePath(IMAPSession *imap, MB_String &filePath, bool header);
// Decode text and store it to buffer or file
void decodeText(IMAPSession *imap, esp_mail_imap_response_data &res);
// Handle atachment parsing and download
bool parseAttachmentResponse(IMAPSession *imap, char *buf, esp_mail_imap_response_data &res);
// Get List
char *getList(char *buf, bool &isList);
// Parse mailbox folder open response
void parseFoldersResponse(IMAPSession *imap, char *buf, bool list);
// Prepare alias (short name) file list for unsupported long file name filesystem
void prepareFileList(IMAPSession *imap, MB_String &filePath);
// Parse capability response
bool parseCapabilityResponse(IMAPSession *imap, const char *buf, int &chunkIdx);
// Parse Idle response
bool parseIdleResponse(IMAPSession *imap);
// Append Fetch UID/Flags string to buffer
void appendFetchString(MB_String &buf, bool uid);
// Parse command response
void parseCmdResponse(IMAPSession *imap, char *buf, PGM_P find);
// Get flags
bool getFlags(IMAPSession *imap, char *buf, esp_mail_imap_response_types type);
// Parse examine response
void parseExamineResponse(IMAPSession *imap, char *buf);
// Handle the error by sending callback and close session
bool handleIMAPError(IMAPSession *imap, int err, bool ret);
// Set Flag
bool mSetFlag(IMAPSession *imap, MB_StringPtr sequenceSet, MB_StringPtr flags, esp_mail_imap_store_flag_type type, bool closeSession, bool silent = false, bool UID = true, int32_t modsequence = -1);
#endif
};
#if defined(ENABLE_IMAP)
class IMAPSession
{
public:
IMAPSession(Client *client);
IMAPSession();
~IMAPSession();
/** Set the tcp timeout.
*
* @param timeoutSec The tcp timeout in seconds.
*/
void setTCPTimeout(unsigned long timeoutSec);
/** Assign custom Client from Arduino Clients.
*
* @param client The pointer to Arduino Client derived class e.g. WiFiClient, EthernetClient or GSMClient.
*/
void setClient(Client *client);
/** Assign TinyGsm Clients.
*
* @param client The pointer to TinyGsmClient.
* @param modem The pointer to TinyGsm modem object. Modem should be initialized and/or set mode before transfering data.
* @param pin The SIM pin.
* @param apn The GPRS APN (Access Point Name).
* @param user The GPRS user.
* @param password The GPRS password.
*/
void setGSMClient(Client *client, void *modem, const char *pin, const char *apn, const char *user, const char *password);
/** Assign the callback function to handle the network connection for custom Client.
*
* @param networkConnectionCB The function that handles the network connection.
*/
void networkConnectionRequestCallback(NetworkConnectionRequestCallback networkConnectionCB);
/** Assign the callback function to handle the network connection status acknowledgement.
*
* @param networkStatusCB The function that handle the network connection status acknowledgement.
*/
void networkStatusRequestCallback(NetworkStatusRequestCallback networkStatusCB);
/** Set the network status acknowledgement.
*
* @param status The network status.
*/
void setNetworkStatus(bool status);
/** Set the BearSSL IO buffer size.
*
* @param rx The BearSSL receive buffer size in bytes.
* @param tx The BearSSL trasmit buffer size in bytes.
*/
void setSSLBufferSize(int rx = -1, int tx = -1);
/** Begin the IMAP server connection.
*
* @param session_config The pointer to Session_Config structured data that keeps
* the server and log in details.
* @param imap_data The pointer to IMAP_Data structured data that keeps the
* operation options.
* @param login The bool option for login after server connection.
* @return The boolean value which indicates the success of operation.
*/
bool connect(Session_Config *session_config, IMAP_Data *imap_data, bool login = true);
/** Log in to IMAP server using Email and password.
*
* @param email The IMAP server account email.
* @param password The IMAP server account password.
* @return The boolean value which indicates the success of operation.
*/
template <typename T1 = const char *, typename T2 = const char *>
bool loginWithPassword(T1 email, T2 password) { return mLogin(toStringPtr(email), toStringPtr(password), false); };
/** Log in to IMAP server using Email and access token.
*
* @param email The IMAP server account email.
* @param token The Access token to log in.
* @return The boolean value which indicates the success of operation.
*/
template <typename T1 = const char *, typename T2 = const char *>
bool loginWithAccessToken(T1 email, T2 token) { return mLogin(toStringPtr(email), toStringPtr(token), true); };
/** Send the client identification to the server
*
* @param identification The pointer to IMAP_Identification structured data that keeps
* the key properties e.g., name, version, os, os_version, vendor, support_url, address,
* date, command, arguments, and environment.
*/
bool id(IMAP_Identification *identification);
/** Return the server ID returns from ID command.
* @return The server ID string.
*/
String serverID();
/** Return the SASL authentication status.
* @return The boolean value indicates SASL authentication status.
*/
bool isAuthenticated();
/** Return the log status.
* @return The boolean value log in status.
*/
bool isLoggedIn();
/** Return firmware update result when attachment filename matches.
* @return The boolean value indicates the firmware update status.
*/
bool isFirmwareUpdateSuccess();
/** Begin the IMAP server connection without authentication.
*
* @param session_config The pointer to Session_Config structured data that keeps
* the server and log in details.
* @param callback The callback function that accepts IMAP_Response as parameter.
* @param tag The tag that pass to the callback function.
* @return The boolean value indicates the success of operation.
*/
template <typename T = const char *>
bool customConnect(Session_Config *session_config, imapResponseCallback callback, T tag = "") { return mCustomConnect(session_config, callback, toStringPtr(tag)); };
/** Close the IMAP session.
*
* @return The boolean value which indicates the success of operation.
*/
bool closeSession();
/** Get TCP connection status.
*
* @return The boolean value indicates the connection status.
*/
bool connected();
/** Set to enable the debug.
*
* @param level The level to enable the debug message
* level = 0, no debugging
* level = 1, basic level debugging
*/
void debug(int level);
/** Get the list of all the mailbox folders since the TCP session was opened
* and user was authenticated.
*
* @param folders The FoldersCollection class that contains the collection of
* the
* FolderInfo structured data.
* @return The boolean value which indicates the success of operation.
*/
bool getFolders(FoldersCollection &folders);
/** Select or open the mailbox folder to search or fetch the message inside.
*
* @param folderName The known mailbox folder name. The default name is INBOX.
* @param readOnly The option to open the mailbox for read only. Set this
* option to false when you wish
* to modify the Flags using the setFlag, addFlag and removeFlag functions.
* @return The boolean value which indicates the success of operation.
*
* @note: the function will exit immediately and return true if the time since previous success folder selection (open)
* with the same readOnly mode, is less than 5 seconds.
*/
template <typename T = const char *>
bool selectFolder(T folderName, bool readOnly = true) { return mSelectFolder(toStringPtr(folderName), readOnly); }
/** Open the mailbox folder to read or search the mesages.
*
* @param folderName The name of known mailbox folder to be opened.
* @param readOnly The option to open the mailbox for reading only. Set this
* option to false when you wish
* to modify the flags using the setFlag, addFlag and removeFlag functions.
* @return The boolean value which indicates the success of operation.
*
* @note: the function will exit immediately and return true if the time since previous success folder selection (open)
* with the same readOnly mode, is less than 5 seconds.
*/
template <typename T = const char *>
bool openFolder(T folderName, bool readOnly = true) { return mOpenFolder(toStringPtr(folderName), readOnly); }
/** Close the mailbox folder that was opened.
*
* @param expunge The option to allow emty the deleted flag set messages in case folder was open with editable mode.
* @return The boolean value which indicates the success of operation.
*/
bool closeFolder(bool expunge = false) { return mCloseFolder(expunge); }
/** Create folder.
*
* @param folderName The name of folder to create.
* @return The boolean value which indicates the success of operation.
*/
template <typename T = const char *>
bool createFolder(T folderName) { return mCreateFolder(toStringPtr(folderName)); }
/** Rename folder.
*
* @param currentFolderName The name of folder to rename.
* @param newFolderName The new name of folder to rename.
* @return The boolean value which indicates the success of operation.
*/
template <typename T1 = const char *, typename T2 = const char *>
bool renameFolder(T1 currentFolderName, T2 newFolderName) { return mRenameFolder(toStringPtr(currentFolderName), toStringPtr(newFolderName)); }
/** Delete folder.
*
* @param folderName The name of folder to delete.
* @return The boolean value which indicates the success of operation.
*/
template <typename T = const char *>
bool deleteFolder(T folderName) { return mDeleteFolder(toStringPtr(folderName)); }
/** Get subscribes mailboxes.
*
* @param reference The reference name.
* @param mailbox The mailbox name with possible wildcards.
* @param folders The return FoldersCollection that contains the folder info e.g., name, attribute and delimiter.
* @return The boolean value which indicates the success of operation.
*/
template <typename T1 = const char *, typename T2 = const char *>
bool getSubscribesMailboxes(T1 reference, T2 mailbox, FoldersCollection &folders) { return mGetSubscribesMailboxes(toStringPtr(reference), toStringPtr(mailbox), folders); }
/** Subscribe mailbox.
*
* @param folderName The name of folder to subscribe.
* @return The boolean value which indicates the success of operation.
*/
template <typename T = const char *>
bool subscribe(T folderName) { return mSubscribe(toStringPtr(folderName)); }
/** Unsubscribe mailbox.
*
* @param folderName The name of folder to unsubscribe.
* @return The boolean value which indicates the success of operation.
*/
template <typename T = const char *>
bool unSubscribe(T folderName) { return mUnSubscribe(toStringPtr(folderName)); }
/** Get UID number in selected or opened mailbox.
*
* @param msgNum The message number or order in the total message numbers.
* @return UID number in selected or opened mailbox.
*
* @note Returns 0 when fail to get UID.
*/
int getUID(int msgNum);
/** Get message flags in selected or opened mailbox.
*
* @param msgNum The message number or order in the total message numbers.
* @return Message flags in selected or opened mailbox.
*
* @note Returns empty string when fail to get flags.
*/
const char *getFlags(int msgNum);
/** Send the custom IMAP command and get the result via callback.
*
* @param cmd The command string.
* @param callback The callback function that accepts IMAP_Response as parameter.
* @param tag The tag string to pass to the callback function.
* @return The boolean value which indicates the success of operation.
*
* @note imap.connect and imap.selectFolder or imap.openFolder are needed to call once prior to call this function.
*/
template <typename T1 = const char *, typename T2 = const char *>
bool sendCustomCommand(T1 cmd, imapResponseCallback callback, T2 tag = "") { return mSendCustomCommand(toStringPtr(cmd), callback, toStringPtr(tag)); }
/** Send the custom IMAP command data string.
*
* @param data The string data.
* @param last The flag represents the last data to send (optional).
* @return The boolean value which indicates the success of operation.
*
* @note Should be used after calling sendCustomCommand("APPEND xxxxxx");
*/
template <typename T = const char *>
bool sendCustomData(T data, bool lastData = false) { return mSendData(toStringPtr(data), lastData, esp_mail_imap_cmd_custom); }
/** Send the custom IMAP command data.
*
* @param data The byte data.
* @param size The data size.
* @param lastData The flag represents the last data to send (optional).
* @return The boolean value which indicates the success of operation.
*
* @note Should be used after calling ssendCustomCommand("APPEND xxxxxx");
*/
bool sendCustomData(uint8_t *data, size_t size, bool lastData = false) { return mSendData(data, size, lastData, esp_mail_imap_cmd_custom); }
/** Copy the messages to the defined mailbox folder.
*
* @param toCopy The pointer to the MessageList class that contains the
* list of messages to copy.
* @param dest The destination folder that the messages to copy to.
* @return The boolean value which indicates the success of operation.
*/
template <typename T = const char *>
bool copyMessages(MessageList *toCopy, T dest) { return mCopyMessages(toCopy, toStringPtr(dest)); }
/** Copy the messages to the defined mailbox folder.
*
* @param sequenceSet The sequence set string i.g., unique identifier (UID) or message sequence number or ranges of UID or sequence number.
* @param UID The option for sequenceSet whether it is UID or message sequence number.
* @param dest The destination folder that the messages to copy to.
* @return The boolean value indicates the success of operation.
*/
template <typename T1 = const char *, typename T2 = const char *>
bool copyMessages(T1 sequenceSet, bool UID, T2 dest) { return mCopyMessagesSet(toStringPtr(sequenceSet), UID, toStringPtr(dest)); }
/** Move the messages to the defined mailbox folder.
*
* @param toMove The pointer to the MessageList class that contains the
* list of messages to move.
* @param dest The destination folder that the messages to move to.
* @return The boolean value which indicates the success of operation.
*/
template <typename T = const char *>
bool moveMessages(MessageList *toCopy, T dest) { return mMoveMessages(toCopy, toStringPtr(dest)); }
/** Move the messages to the defined mailbox folder.
*
* @param sequenceSet The sequence set string i.g., unique identifier (UID) or message sequence number or ranges of UID or sequence number.
* @param UID The option for sequenceSet whether it is UID or message sequence number.
* @param dest The destination folder that the messages to move to.
* @return The boolean value indicates the success of operation.
*/
template <typename T1 = const char *, typename T2 = const char *>
bool moveMessages(T1 sequenceSet, bool UID, T2 dest) { return mMoveMessagesSet(toStringPtr(sequenceSet), UID, toStringPtr(dest)); }
/** Delete the messages in the opened mailbox folder.
*
* @param toDelete The pointer to the MessageList class that contains the
* list of messages to delete.
* @param expunge The boolean option to expunge all messages.
* @param modsequence The int32_t option for UNCHANGESINCE conditional test.
* @return The boolean value which indicates the success of operation.
*
* The modsequence value can be used only if IMAP server supports Conditional STORE extension
* and the selected mailbox supports modsequences.
*/
bool deleteMessages(MessageList *toDelete, bool expunge = false, int32_t modsequence = -1) { return mDeleteMessages(toDelete, expunge, modsequence); }
/** Delete the messages in the opened mailbox folder.
*
* @param sequenceSet The sequence set string i.g., unique identifier (UID) or message sequence number or ranges of UID or sequence number.
* @param UID The option for sequenceSet whether it is UID or message sequence number.
* @param expunge The boolean option to expunge all messages.
* @param modsequence The int32_t option for UNCHANGESINCE conditional test.
* @return The boolean value which indicates the success of operation.
*
* The modsequence value can be used only if IMAP server supports Conditional STORE extension
* and the selected mailbox supports modsequences.
*/
template <typename T = const char *>
bool deleteMessages(T sequenceSet, bool UID, bool expunge = false, int32_t modsequence = -1) { return mDeleteMessagesSet(toStringPtr(sequenceSet), UID, expunge, modsequence); }
/** Get the quota root's resource usage and limits.
*
* @param quotaRoot The quota root to get.
* @param info The pointer to IMAP_Quota_Root_Info that contains quota root's resource name, usage and limit.
* @return The boolean value which indicates the success of operation.
*/
template <typename T = const char *>
bool getQuota(T quotaRoot, IMAP_Quota_Root_Info *info) { return mGetSetQuota(toStringPtr(quotaRoot), info, true); }
/** Set the quota root's resource usage and limits.
*
* @param quotaRoot The quota root to set.
* @param data The pointer to IMAP_Quota_Root_Info that contains quota root's resource name, usage and limit.
* @return The boolean value which indicates the success of operation.
*/
template <typename T = const char *>
bool setQuota(T quotaRoot, IMAP_Quota_Root_Info *data) { return mGetSetQuota(toStringPtr(quotaRoot), data, false); }
/** Get the list of quota roots for the named mailbox.
*
* @param mailbox The mailbox name.
* @param quotaRootsList The pointer to IMAP_Quota_Roots_List that contains the list of IMAP_Quota_Root_Info.
* @return The boolean value which indicates the success of operation.
*/
template <typename T = const char *>
bool getQuotaRoot(T mailbox, IMAP_Quota_Roots_List *quotaRootsList) { return mGetQuotaRoots(toStringPtr(mailbox), quotaRootsList); }
/** Get the ACLs for a mailbox.
*
* @param mailbox The mailbox name.
* @param aclList The pointer to the returning IMAP_Rights_List object.
* @return The boolean value which indicates the success of operation.
*/
template <typename T = const char *>
bool getACL(T mailbox, IMAP_Rights_List *aclList) { return mManageACL(toStringPtr(mailbox), aclList, nullptr, toStringPtr(""), esp_mail_imap_cmd_get_acl); };
/** Get the ACLs for a mailbox.
*
* @param mailbox The mailbox name.
* @param acl The pointer to the acl IMAP_Rights_Info to set.
* @return The boolean value which indicates the success of operation.
*/
template <typename T = const char *>
bool setACL(T mailbox, IMAP_Rights_Info *acl) { return mManageACL(toStringPtr(mailbox), nullptr, acl, toStringPtr(""), esp_mail_imap_cmd_set_acl); };
/** Delete the ACLs set for identifier on mailbox.
*
* @param mailbox The mailbox name.
* @param identifier The identifier (user) to remove the rights.
* @return The boolean value which indicates the success of operation.
*/
template <typename T1 = const char *, typename T2 = const char *>
bool deleteACL(T1 mailbox, T2 identifier) { return mManageACL(toStringPtr(mailbox), nullptr, nullptr, toStringPtr(identifier), esp_mail_imap_cmd_delete_acl); };
/** Show my ACLs for a mailbox.
*
* @param mailbox The mailbox name.
* @param acl The pointer to the returning IMAP_Rights_Info object.
* @return The boolean value which indicates the success of operation.
*/
template <typename T = const char *>
bool myRights(T mailbox, IMAP_Rights_Info *acl) { return mManageACL(toStringPtr(mailbox), nullptr, acl, toStringPtr(""), esp_mail_imap_cmd_my_rights); };
/** Returns IMAP namespaces.
*
* @param mailbox The mailbox name.
* @param ns The pointer to the returning IMAP_Namespaces_List object.
* @return The boolean value which indicates the success of operation.
*/
bool getNamespace(IMAP_Namespaces_List *ns) { return mNamespace(ns); };
/** Enable IMAP capability.
*
* @param capability The mailbox name.
* @return The boolean value which indicates the success of operation.
*/
template <typename T = const char *>
bool enable(T capability) { return mEnable(toStringPtr(capability)); };
/** Listen for the selected or open mailbox for updates.
* @return The boolean value which indicates the success of operation.
*/
bool listen() { return mListen(false); };
/** Stop listen for the mailbox for updates.
* @return The boolean value which indicates the success of operation.
*/
bool stopListen() { return mStopListen(false); };
/** Check for the selected or open mailbox updates.
* @return The boolean value which indicates the changes status of mailbox.
*/
bool folderChanged();
/** Send NOOP command to IMAP server.
* @return The boolean value which indicates the success of operation.
*/
bool noop();
/** Assign the callback function that returns the operating status when
* fetching or reading the Email.
*
* @param imapCallback The function that accepts the imapStatusCallback as
* parameter.
*/
void callback(imapStatusCallback imapCallback);
/** Assign the callback function to decode the string based on the character set.
*
* @param callback The function that accepts the pointer to IMAP_Decoding_Info as parameter.
*/
void characterDecodingCallback(imapCharacterDecodingCallback callback);
/** Assign the callback function that returns the MIME data stream from
* fetching or reading the Email.
*
* @param mimeDataStreamCallback The function that accepts the MIME_Stream_Info as
* parameter.
*/
void mimeDataStreamCallback(MIMEDataStreamCallback mimeDataStreamCallback);
/** Determine if no message body contained in the search result and only the
* message header is available.
*/
bool headerOnly();
/** Get the message list from search or fetch the Emails
*
* @return The IMAP_MSG_List structured data which contains text and html
* contents,
* attachments, inline images, embedded rfc822 messages details for each
* message.
*/
IMAP_MSG_List data();
/** Get the details of the selected or opned mailbox folder
*
* @return The SelectedFolderInfo class which contains the info about flags,
* total messages, next UID,
* search count and the available messages count.
*/
SelectedFolderInfo selectedFolder();
/** Get the error details when readingg the Emails
*
* @return The string of error details.
*/
String errorReason();
/** Get the operating status error code.
*
* @return The int value of operating status error code.
*
* The negative value indicated error.
* See src/ESP_Mail_Error.h and extras/MB_FS.h
*/
int errorCode();
/** Clear all the cache data stored in the IMAP session object.
*/
void empty();
/** Get the status of message fetching and searching.
*
* @return The IMAP_Status object contains the fetching and searching statuses.
*/
IMAP_Status status();
/** Get the JSON string of file name list of files that stored in SD card.
*
* @return The JSON string of filenames.
* @note This will available only when standard SD library was used and file storage is SD.
*/
String fileList();
/** Set the current timestamp.
*
* @param ts The current timestamp.
* @param gmtOffset The GMT offset.
*/
void setSystemTime(time_t ts, float gmtOffset = 0);
/** Setup TCP KeepAlive for internal TCP client.
*
* @param tcpKeepIdleSeconds lwIP TCP Keepalive idle in seconds.
* @param tcpKeepIntervalSeconds lwIP TCP Keepalive interval in seconds.
* @param tcpKeepCount lwIP TCP Keepalive count.
*
* For the TCP (KeepAlive) options, see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/lwip.html#tcp-options.
*
* If value of one of these parameters is zero, the TCP KeepAlive will be disabled.
*
* You can check the server connecting status, by exexuting <IMAPSession>.connected() which will return true when connection to the server is still alive.
*/
void keepAlive(int tcpKeepIdleSeconds, int tcpKeepIntervalSeconds, int tcpKeepCount);
/** Get TCP KeepAlive status.
*
* @return Boolean status of TCP KeepAlive.
*/
bool isKeepAlive();
friend class ESP_Mail_Client;
friend class foldderList;
private:
// Log in to IMAP server
bool mLogin(MB_StringPtr email, MB_StringPtr password, bool isToken);
// Clear message data
void clearMessageData();
// Check for valid UID or set wildcard * as UID
void checkUID();
// Check for valid saving file path or prepend /
void checkPath();
// Get message item by index
void getMessages(uint16_t messageIndex, struct esp_mail_imap_msg_item_t &msg);
// Get RFC822 message item by index
void getRFC822Messages(uint16_t messageIndex, struct esp_mail_imap_msg_item_t &msg);
// Close mailbox
bool closeMailbox(bool expunge = false);
// Open mailbox
bool openMailbox(MB_StringPtr folder, esp_mail_imap_auth_mode mode, bool waitResponse, bool unselect);
// Get folders list
bool getMailboxes(FoldersCollection &folders);
// Get subscribes mailboxes
bool mGetSubscribesMailboxes(MB_StringPtr reference, MB_StringPtr mailbox, FoldersCollection &folders);
// Subscribe the mailbox
bool mSubscribe(MB_StringPtr folder);
// Unsubscribe the mailbox
bool mUnSubscribe(MB_StringPtr folder);
// Get UID
int mGetUID(int msgNum);
// Fetch by sequence set
bool mFetchSequenceSet();
// Return string from TAG prepended command
MB_String prependTag(PGM_P cmd, PGM_P tag = NULL);
// Check capabilities
bool checkCapabilities();
// Listen mailbox changes
bool mListen(bool recon);
// Stop listen mailbox
bool mStopListen(bool recon);
// Send custom command
bool mSendCustomCommand(MB_StringPtr cmd, imapResponseCallback callback, MB_StringPtr tag);
// Send data after sending APPEND command
bool mSendData(MB_StringPtr data, bool lastData, esp_mail_imap_command cmd);
// Send data after sending APPEND command
bool mSendData(uint8_t *data, size_t size, bool lastData, esp_mail_imap_command cmd);
// Delete folder
bool mDeleteFolder(MB_StringPtr folderName);
// Create folder
bool mCreateFolder(MB_StringPtr folderName);
// Rename folder
bool mRenameFolder(MB_StringPtr currentFolderName, MB_StringPtr newFolderName);
// Copy message
bool copyMsg(MessageList *toCopy, const char *sequenceSet, bool UID, MB_StringPtr dest);
// Copy message
bool mCopyMessages(MessageList *toCopy, MB_StringPtr dest);
// Copy message using sequence set
bool mCopyMessagesSet(MB_StringPtr sequenceSet, bool UID, MB_StringPtr dest);
// Move message
bool moveMsg(MessageList *toMove, const char *sequenceSet, bool UID, MB_StringPtr dest);
// Move message
bool mMoveMessages(MessageList *toMove, MB_StringPtr dest);
// Move message using sequence set
bool mMoveMessagesSet(MB_StringPtr sequenceSet, bool UID, MB_StringPtr dest);
// Check for conditional STORE extention support
bool isCondStoreSupported();
// Check for mailbox mod-sequence support
bool isModseqSupported();
// add UNCHANGEDSINCE STORE modifier and CHANGEDSINCE FETCH modifier to command
void addModifier(MB_String &cmd, esp_mail_imap_command_types type, int32_t modsequence);
// Delete message
bool deleteMsg(MessageList *toDelete, const char *sequenceSet, bool UID, bool expunge, int32_t modsequence = -1);
// Delete messages
bool mDeleteMessages(MessageList *toDelete, bool expunge = false, int32_t modsequence = -1);
// Delete messages
bool mDeleteMessagesSet(MB_StringPtr sequenceSet, bool UID, bool expunge = false, int32_t modsequence = -1);
// Get or set the quota root's resource usage and limits.
bool mGetSetQuota(MB_StringPtr quotaRoot, IMAP_Quota_Root_Info *data, bool getMode);
// Parse the IMAP_Quota_Root_info
void mParseQuota(const char *quota, IMAP_Quota_Root_Info *data);
// Get the list of quota roots for the named mailbox.
bool mGetQuotaRoots(MB_StringPtr mailbox, IMAP_Quota_Roots_List *quotaRootsList);
// Get or set ACL.
bool mManageACL(MB_StringPtr mailbox, IMAP_Rights_List *acl_list, IMAP_Rights_Info *acl, MB_StringPtr identifier, esp_mail_imap_command type);
// Parse ACL
void parseACL(MB_String &acl_str, IMAP_Rights_List *right_list);
// parse Rights
void parseRights(MB_String &righs_str, IMAP_Rights_Info *info);
// Get Rights from IMAP_Rights_Info
void getRights(MB_String &righs_str, IMAP_Rights_Info *info);
// Get namespace
bool mNamespace(IMAP_Namespaces_List *ns);
// Enable the IMAP capability
bool mEnable(MB_StringPtr capability);
// Parse namespaces
void parseNamespaces(MB_String &ns_str, IMAP_Namespaces *ns);
// Close folder
bool mCloseFolder(bool expunge = false);
// Open folder
bool mOpenFolder(MB_StringPtr folderName, bool readOnly);
// Select folder
bool mSelectFolder(MB_StringPtr folderName, bool readOnly);
// Custom TCP connection
bool mCustomConnect(Session_Config *session_config, imapResponseCallback callback, MB_StringPtr tag);
// Append ID list to buffer
void appendIdList(MB_String &list, IMAP_Identification *identification);
// Handle connection
bool handleConnection(Session_Config *session_config, IMAP_Data *imap_data, bool &ssl);
// Start TCP connection
bool connect(bool &ssl);
// Print features not supported debug error message
void printDebugNotSupported();
bool _sessionSSL = false;
bool _sessionLogin = false;
bool _loginStatus = false;
unsigned long _last_polling_error_ms = 0;
unsigned long _last_host_check_ms = 0;
unsigned long _last_server_connect_ms = 0;
unsigned long _last_network_error_ms = 0;
unsigned long tcpTimeout = TCP_CLIENT_DEFAULT_TCP_TIMEOUT_SEC;
struct esp_mail_imap_response_status_t _responseStatus;
int _cMsgIdx = 0;
int _cPartIdx = 0;
int _totalRead = 0;
_vectorImpl<struct esp_mail_message_header_t> _headers;
esp_mail_imap_command _imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_sasl_login;
esp_mail_imap_command _prev_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_sasl_login;
esp_mail_imap_command _imap_custom_cmd = esp_mail_imap_cmd_custom;
esp_mail_imap_command _prev_imap_custom_cmd = esp_mail_imap_cmd_custom;
bool _idle = false;
MB_String _cmd;
_vectorImpl<struct esp_mail_imap_multipart_level_t> _multipart_levels;
int _rfc822_part_count = 0;
bool _unseen = false;
bool _readOnlyMode = true;
bool _msgDownload = false;
bool _attDownload = false;
bool _storageReady = false;
bool _storageChecked = false;
bool _auth_capability[esp_mail_auth_capability_maxType];
bool _feature_capability[esp_mail_imap_read_capability_maxType];
Session_Config *_session_cfg;
_vectorImpl<int> _configPtrList;
MB_String _currentFolder;
bool _mailboxOpened = false;
unsigned long _lastSameFolderOpenMillis = 0;
MB_String _nextUID;
MB_String _unseenMsgIndex;
MB_String _flags_tmp;
MB_String _quota_tmp;
MB_String _quota_root_tmp;
MB_String _acl_tmp;
MB_String _ns_tmp;
MB_String _server_id_tmp;
MB_String _sdFileList;
struct esp_mail_imap_data_config_t *_imap_data = nullptr;
int _userHeaderOnly = -1;
bool _headerOnly = true;
bool _uidSearch = false;
bool _headerSaved = false;
bool _debug = false;
int _debugLevel = 0;
bool _secure = false;
bool _authenticated = false;
bool _isFirmwareUpdated = false;
imapStatusCallback _statusCallback = NULL;
imapResponseCallback _customCmdResCallback = NULL;
MIMEDataStreamCallback _mimeDataStreamCallback = NULL;
imapCharacterDecodingCallback _charDecCallback = NULL;
_vectorImpl<struct esp_mail_imap_msg_num_t> _imap_msg_num;
esp_mail_session_type _sessionType = esp_mail_session_type_imap;
FoldersCollection _folders;
SelectedFolderInfo _mbif;
int _uid_tmp = 0;
int _lastProgress = -1;
ESP_Mail_TCPClient client;
IMAP_Status _cbData;
};
#endif
#if defined(ENABLE_SMTP)
class SendingResult
{
private:
_vectorImpl<SMTP_Result> _result;
void add(SMTP_Result *r)
{
_result.push_back(*r);
}
public:
friend class SMTPSession;
friend class ESP_Mail_Client;
SendingResult(){};
~SendingResult() { clear(); };
void clear()
{
for (size_t i = 0; i < _result.size(); i++)
{
_result[i].recipients.clear();
_result[i].subject.clear();
_result[i].timestamp = 0;
_result[i].completed = false;
}
_result.clear();
}
SMTP_Result getItem(size_t index)
{
SMTP_Result r;
if (index < _result.size())
return _result[index];
return r;
}
size_t size() { return _result.size(); };
};
class SMTPSession
{
public:
SMTPSession(Client *client);
SMTPSession();
~SMTPSession();
/** Set the tcp timeout.
*
* @param timeoutSec The tcp timeout in seconds.
*/
void setTCPTimeout(unsigned long timeoutSec);
/** Assign custom Client from Arduino Clients.
*
* @param client The pointer to Arduino Client derived class e.g. WiFiClient, EthernetClient or GSMClient.
*/
void setClient(Client *client);
/** Assign TinyGsm Clients.
*
* @param client The pointer to TinyGsmClient.
* @param modem The pointer to TinyGsm modem object. Modem should be initialized and/or set mode before transfering data.
* @param pin The SIM pin.
* @param apn The GPRS APN (Access Point Name).
* @param user The GPRS user.
* @param password The GPRS password.
*/
void setGSMClient(Client *client, void *modem, const char *pin, const char *apn, const char *user, const char *password);
/** Assign the callback function to handle the network connection for custom Client.
*
* @param networkConnectionCB The function that handles the network connection.
*/
void networkConnectionRequestCallback(NetworkConnectionRequestCallback networkConnectionCB);
/** Assign the callback function to handle the network connection status acknowledgement.
*
* @param networkStatusCB The function that handle the network connection status acknowledgement.
*/
void networkStatusRequestCallback(NetworkStatusRequestCallback networkStatusCB);
/** Set the network status acknowledgement.
*
* @param status The network status.
*/
void setNetworkStatus(bool status);
/** Set the BearSSL IO buffer size.
*
* @param rx The BearSSL receive buffer size in bytes.
* @param tx The BearSSL trasmit buffer size in bytes.
*/
void setSSLBufferSize(int rx = -1, int tx = -1);
/** Begin the SMTP server connection.
*
* @param session_config The pointer to Session_Config structured data that keeps
* the server and log in details.
* @param login The bool option for login after server connection.
* @return The boolean value indicates the success of operation.
*/
bool connect(Session_Config *session_config, bool login = true);
/** Log in to SMTP server using Email and password.
*
* @param email The SMTP server account email.
* @param password The SMTP server account password.
* @return The boolean value which indicates the success of operation.
*/
template <typename T1 = const char *, typename T2 = const char *>
bool loginWithPassword(T1 email, T2 password) { return mLogin(toStringPtr(email), toStringPtr(password), false); };
/** Log in to SMTP server using Email and access token.
*
* @param email The SMTP server account email.
* @param token The Access token to log in.
* @return The boolean value which indicates the success of operation.
*/
template <typename T1 = const char *, typename T2 = const char *>
bool loginWithAccessToken(T1 email, T2 token) { return mLogin(toStringPtr(email), toStringPtr(token), true); };
/** Return the SASL authentication status.
* @return The boolean value indicates SASL authentication status.
*/
bool isAuthenticated();
/** Return the log status.
* @return The boolean value indicates log in status.
*/
bool isLoggedIn();
/** Begin the SMTP server connection without authentication.
*
* @param session_config The pointer to Session_Config structured data that keeps
* the server and log in details.
* @param callback The callback function that accepts the SMTP_Response as parameter.
* @param commandID The command identifier number that will pass to the callback.
* @return The int value of status code.
*
* @note If commandID was not set or set to -1, the command identifier will be auto increased started from zero.
*/
int customConnect(Session_Config *session_config, smtpResponseCallback callback, int commandID = -1);
/** Close the SMTP session.
*
*/
bool closeSession();
/** Get TCP connection status.
*
* @return The boolean value indicates the connection status.
*/
bool connected();
/** Send the custom SMTP command and get the result via callback.
*
* @param cmd The command string.
* @param callback The function that accepts the SMTP_Response as parameter.
* @param commandID The command identifier number that will pass to the callback.
* @return The integer value of response code.
*
* @note smtp.connect or smtp.customConnect is needed to call once prior to call this function.
*
* If commandID was not set or set to -1, the command identifier will be auto increased started from zero.
*/
template <typename T = const char *>
int sendCustomCommand(T cmd, smtpResponseCallback callback, int commandID = -1) { return mSendCustomCommand(toStringPtr(cmd), callback, commandID); }
/** Send the custom SMTP command data string.
*
* @param data The string data.
* @return The boolean value which indicates the success of operation.
*
* @note Should be used after calling sendCustomCommand("DATA");
*/
template <typename T = const char *>
bool sendCustomData(T data) { return mSendData(toStringPtr(data)); }
/** Send the custom SMTP command data.
*
* @param data The byte data.
* @param size The data size.
* @return The boolean value which indicates the success of operation.
*
* @note Should be used after calling sendCustomCommand("DATA");
*/
bool sendCustomData(uint8_t *data, size_t size) { return mSendData(data, size); }
/** Set to enable the debug.
*
* @param level The level to enable the debug message
* level = 0, no debugging
* level = 1, basic level debugging
*/
void debug(int level);
/** Get the error details when sending the Email
*
* @return The string of error details.
*/
String errorReason();
/** Get the SMTP server response status code.
*
* @return The int value of SMTP server response status code.
*
* See RFC 5321 standard's documentation.
*/
int statusCode();
/** Get the SMTP server response status message.
*
* @return The int value of SMTP server response status message.
*
*/
String statusMessage();
/** Get the operating status error code.
*
* @return The int value of operating status error code.
*
* The negative value indicated error.
* See src/ESP_Mail_Error.h and extras/MB_FS.h
*/
int errorCode();
/** Set the Email sending status callback function.
*
* @param smtpCallback The callback function that accept the
* smtpStatusCallback param.
*/
void callback(smtpStatusCallback smtpCallback);
/** Get the status of message fetching and searching.
*
* @return The SMTP_Status object contains the sending status.
*/
SMTP_Status status();
/** Set the current timestamp.
*
* @param ts The current timestamp.
* @param gmtOffset The GMT offset.
*/
void setSystemTime(time_t ts, float gmtOffset = 0);
/** Setup TCP KeepAlive for internal TCP client.
*
* @param tcpKeepIdleSeconds lwIP TCP Keepalive idle in seconds.
* @param tcpKeepIntervalSeconds lwIP TCP Keepalive interval in seconds.
* @param tcpKeepCount lwIP TCP Keepalive count.
*
* For the TCP (KeepAlive) options, see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/lwip.html#tcp-options.
*
* If value of one of these parameters is zero, the TCP KeepAlive will be disabled.
*
* You can check the server connecting status, by exexuting <SMTPSession>.connected() which will return true when connection to the server is still alive.
*/
void keepAlive(int tcpKeepIdleSeconds, int tcpKeepIntervalSeconds, int tcpKeepCount);
/** Get TCP KeepAlive status.
*
* @return Boolean status of TCP KeepAlive.
*/
bool isKeepAlive();
SendingResult sendingResult;
friend class ESP_Mail_Client;
private:
bool _sessionSSL = false;
bool _sessionLogin = false;
struct esp_mail_smtp_response_status_t _responseStatus;
int _sentSuccessCount = 0;
int _sentFailedCount = 0;
bool _chunkedEnable = false;
int _chunkCount = 0;
uint32_t ts = 0;
unsigned long tcpTimeout = TCP_CLIENT_DEFAULT_TCP_TIMEOUT_SEC;
esp_mail_smtp_command _smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_greeting;
bool _auth_capability[esp_mail_auth_capability_maxType];
bool _feature_capability[esp_mail_smtp_send_capability_maxType];
Session_Config *_session_cfg = NULL;
_vectorImpl<int> _configPtrList;
bool _debug = false;
int _debugLevel = 0;
bool _secure = false;
bool _authenticated = false;
bool _loginStatus = false;
bool _waitForAuthenticate = false;
bool _canForward = false;
smtpStatusCallback _statusCallback = NULL;
smtpResponseCallback _customCmdResCallback = NULL;
int _commandID = -1;
bool _sdStorageReady = false;
bool _flashStorageReady = false;
bool _sdStorageChecked = false;
bool _flashStorageChecked = false;
esp_mail_session_type _sessionType = esp_mail_session_type_smtp;
SMTP_Status _cbData;
struct esp_mail_smtp_msg_type_t _msgType;
int _lastProgress = -1;
ESP_Mail_TCPClient client;
// Start TCP connection
bool connect(bool &ssl);
// Log in to SMTP server
bool mLogin(MB_StringPtr email, MB_StringPtr password, bool isToken);
// Handle TCP connection
bool handleConnection(Session_Config *session_config, bool &ssl);
// Send custom command
int mSendCustomCommand(MB_StringPtr cmd, smtpResponseCallback callback, int commandID = -1);
// Send data after sending DATA command
bool mSendData(MB_StringPtr data);
// Send data after sending DATA command
bool mSendData(uint8_t *data, size_t size);
};
#endif
#if defined(ENABLE_SMTP) && defined(ENABLE_IMAP)
class ESP_Mail_Message : public SMTP_Message
{
public:
ESP_Mail_Message(){};
~ESP_Mail_Message(){};
};
#endif
extern ESP_Mail_Client MailClient;
#endif /* ESP_MAIL_CLIENT_H */