update sendmail

This commit is contained in:
gemu2015 2021-02-16 11:33:22 +01:00
parent e54487fd24
commit 218b5101b4
76 changed files with 30120 additions and 12627 deletions

12
lib/lib_div/lib_mail/.github/FUNDING.yml vendored Executable file
View File

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: ["https://www.paypal.me/mobizt"] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

17
lib/lib_div/lib_mail/.github/stale.yml vendored Executable file
View File

@ -0,0 +1,17 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 20
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 5
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
# Label to use when marking an issue as stale
staleLabel: wontfix
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2019 mobizt
Copyright (c) 2021 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

258
lib/lib_div/lib_mail/README.md Executable file
View File

@ -0,0 +1,258 @@
# Mail Client Arduino Library for ESP32 and ESP8266 v 1.0.13
[![Join the chat at https://gitter.im/mobizt/ESP_Mail_Client](https://badges.gitter.im/mobizt/ESP_Mail_Client.svg)](https://gitter.im/mobizt/ESP_Mail_Client?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
The complete and secure Mail Client for ESP32 and ESP8266 devices for sending and reading the Email through the SMTP and IMAP servers.
With this library, the devices can both send and read the Email with many types of attachments supported and provides more reliable and flexibilities of usages.
The library was tested and work well with ESP32s and ESP8266s based modules.
This library was developed to replace the deprecated ESP32 Mail Client library with more options and features, better reliability and also conforms to the RFC standards.
![ESP32 Mail](/media/images/esp-mail-client.svg)
Copyright (c) 2021 K. Suwatchai (Mobizt).
# Features
* Support Espressif ESP32 and ESP8266 MCUs based devices.
* Support TCP session reusage.
* Support PLAIN, LOGIN and XOAUTH2 authentication mechanisms.
* Secured connection with SSL and TLS.
* Support mailbox selection for Email reading and searching.
* Support the content encodings e.g. quoted-printable and base64.
* Support the content decodings e.g. base64, UTF-8, UTF-7, quoted-printable, ISO-8859-1 (latin1) and ISO-8859-11 (Thai).
* Support many types of embedded contents e.g. inline images, attachments, parallel media attachments and RFC822 message.
* Support full debuging.
* Support SPIFFS and SD card for file storages.
* Support Ethernet (ESP32).
* Customizable operating configurations (see the examples for the usages)
## Tested Devices
This following devices were tested.
* Sparkfun ESP32 Thing
* NodeMCU-32
* WEMOS LOLIN32
* TTGO T8 V1.8
* M5Stack ESP32
* NodeMCU ESP8266
* Wemos D1 Mini (ESP8266)
## Prerequisites
The library requires Arduino's ESP32 or ESP8266 Core SDK to be installed based on the platform.
The latest Core SDK is recommended. For ESP8266, the Core SDK version 2.6.3 or later is recommended.
The ESP8266 Core SDK version 2.5.x and earlier are not supported.
## Instalation
Click on **Clone or download** dropdown at the top of repository, select **Download ZIP** and save file on your computer.
From Arduino IDE, goto menu **Sketch** -> **Include Library** -> **Add .ZIP Library...** and choose **ESP-Mail-Client-master.zip** that previously downloaded.
Go to menu **Files** -> **Examples** -> **ESP-Mail-Client-master** and choose one from examples
## Usage
See [Full Examples](/examples) for complete usages.
See [Function Description](/src/README.md) for all available functions.
The following examples showed the minimum usage which many options are not configured.
The examples in the examples folder provide the full options usages.
### Send the Email
```C++
// Include ESP Mail Client library (this library)
#include <ESP_Mail_Client.h>
// Define the SMTP Session object which used for SMTP transsport
SMTPSession smtp;
// Define the session config data which used to store the TCP session configuration
ESP_Mail_Session session;
// Set the session config
session.server.host_name = "smtp.office365.com"; //for outlook.com
session.server.port = 587;
session.login.email = "your Email address"; //set to empty for no SMTP Authentication
session.login.password = "your Email password"; //set to empty for no SMTP Authentication
session.login.user_domain = "client domain or ip e.g. mydomain.com";
// Define the SMTP_Message class variable to handle to message being transport
SMTP_Message message;
// Set the message headers
message.sender.name = "My Mail";
message.sender.email = "sender or your Email address";
message.subject = "Test sending Email";
message.addRecipient("name1", "email1");
message.addRecipient("name2", "email2");
message.addCc("email3");
message.addBcc("email4");
// Set the message content
message.text.content = "This is simple plain text message";
//Base64 data of image
const char *greenImg = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAoUlEQVR42u3RAQ0AMAgAoJviyWxtAtNYwzmoQGT/eqwRQoQgRAhChCBECEKECBGCECEIEYIQIQgRghCECEGIEIQIQYgQhCBECEKEIEQIQoQgBCFCECIEIUIQIgQhCBGCECEIEYIQIQhBiBCECEGIEIQIQQhChCBECEKEIEQIQhAiBCFCECIEIUIQghAhCBGCECEIEYIQIUKEIEQIQoQg5LoBBaDPbQYiMoMAAAAASUVORK5CYII=";
// Define the attachment data
SMTP_Attachment att;
// Set the attatchment info
att.descr.filename = "green.png";
att.descr.mime = "image/png";
att.blob.data = (uint8_t *)greenImg;
att.blob.size = strlen(greenImg);
// Set the transfer encoding to base64
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;
// We set the content encoding to match the above greenImage data
att.descr.content_encoding = Content_Transfer_Encoding::enc_base64;
// Add attachment to the message
message.addAttachment(att);
// Connect to server with the session config
smtp.connect(&session);
// Start sending Email and close the session
if (!MailClient.sendMail(&smtp, &message))
Serial.println("Error sending Email, " + smtp.errorReason());
```
### Read the Email
```C++
// Include ESP Mail Client library (this library)
#include <ESP_Mail_Client.h>
// Define the IMAP Session object which used for IMAP transsport
IMAP_Config config;
// Define the session config data which used to store the TCP session configuration
ESP_Mail_Session session;
// Set the session config
session.server.host_name = "outlook.office365.com"; //for outlook.com
session.server.port = 993;
session.login.email = "your Email address";
session.login.password = "your Email password";
// Define the config class variable for searching or fetching operation and store the messsagess data
IMAP_Config config;
// Define the message UID which required to fetch or read the message
config.fetch.uid = "100";
// Define the empty search criteria to disable the messsage search
config.search.criteria = "";
// Set to enable the message content which will be stored in the IMAP_Config data
config.enable.html = true;
config.enable.text = true;
// Connect to the server with the defined session and options
imap.connect(&session, &config);
// Open or select the mailbox folder to read the message
imap.selectFolder("INBOX");
// Read the Email and close the session
MailClient.readMail(&imap);
// Get the message(s) list
IMAP_MSG_List msgList = imap.data();
for (size_t i = 0; i < msgList.msgItems.size(); i++)
{
// Iterate to get each message data through the message item data
IMAP_MSG_Item msg = msgList.msgItems[i];
Serial.println("################################");
Serial.printf("Messsage Number: %s\n", msg.msgNo);
Serial.printf("Messsage UID: %s\n", msg.UID);
Serial.printf("Messsage ID: %s\n", msg.ID);
Serial.printf("Accept Language: %s\n", msg.acceptLang);
Serial.printf("Content Language: %s\n", msg.contentLang);
Serial.printf("From: %s\n", msg.from);
Serial.printf("From Charset: %s\n", msg.fromCharset);
Serial.printf("To: %s\n", msg.to);
Serial.printf("To Charset: %s\n", msg.toCharset);
Serial.printf("CC: %s\n", msg.cc);
Serial.printf("CC Charset: %s\n", msg.ccCharset);
Serial.printf("Date: %s\n", msg.date);
Serial.printf("Subject: %s\n", msg.subject);
Serial.printf("Subject Charset: %s\n", msg.subjectCharset);
// If the message body is available
if (!imap.headerOnly())
{
Serial.printf("Text Message: %s\n", msg.text.content);
Serial.printf("Text Message Charset: %s\n", msg.text.charSet);
Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
Serial.printf("HTML Message: %s\n", msg.html.content);
Serial.printf("HTML Message Charset: %s\n", msg.html.charSet);
Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
}
}
```
## License
The MIT License (MIT)
Copyright (c) 2021 K. Suwatchai (Mobizt)
Permission is hereby granted, free of charge, to any person returning 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.

View File

@ -0,0 +1 @@
theme: jekyll-theme-cayman

View File

@ -0,0 +1,130 @@
/**
* This example showed how to copy messages from the opened mailbox folder to other folder.
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "################"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "################"
#define AUTHOR_PASSWORD "################"
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(IMAPSession &imap);
/* The IMAP Session object used for Email reading */
IMAPSession imap;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
imap.debug(1);
/* Declare the session config data */
ESP_Mail_Session session;
/* Set the session config */
session.server.host_name = IMAP_HOST;
session.server.port = IMAP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
/* Setup the configuration for searching or fetching operation and its result */
IMAP_Config config;
/* Connect to server with the session and config */
if (!imap.connect(&session, &config))
return;
/* {Optional] */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder("INBOX"))
return;
/* Define the MessageList class to add the message to copy */
MessageList toCopy;
/* Add message uid to copy to the list */
toCopy.add(3);
toCopy.add(4);
//imap.createFolder("test");
/* Copy all messages in the list to the folder "test" */
if (imap.deleteMessages(&toCopy, "test"))
Serial.println("Messages copied");
/* Delete all messages in the list from the opened folder (move to trash) */
//imap.deleteMessages(&toCopy);
//imap.deleteolder("test");
}
void loop()
{
}

View File

@ -0,0 +1,125 @@
/**
* This example showed how to delete messages from the opened mailbox folder.
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "################"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "################"
#define AUTHOR_PASSWORD "################"
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(IMAPSession &imap);
/* The IMAP Session object used for Email reading */
IMAPSession imap;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
imap.debug(1);
/* Declare the session config data */
ESP_Mail_Session session;
/* Set the session config */
session.server.host_name = IMAP_HOST;
session.server.port = IMAP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
/* Setup the configuration for searching or fetching operation and its result */
IMAP_Config config;
/* Connect to server with the session and config */
if (!imap.connect(&session, &config))
return;
/* {Optional] */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder("INBOX"))
return;
/* Define the MessageList class to add the message to delete */
MessageList toDelete;
/* Add message uid to delete to the list */
toDelete.add(10);
toDelete.add(12);
/* Delete all messages in the list (move to trash) */
if(imap.deleteMessages(&toDelete))
Serial.println("Messages deeted");
/* Delete all messages permanently by assign the second param to true*/
//imap.deleteMessages(&toDelete, true);
}
void loop()
{
}

View File

@ -0,0 +1,370 @@
/**
* This example will log in with the SASL XOAUTH2 mechanisme using OAuth2.0 access token.
*
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "################"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The user Email for OAuth2.0 access token */
#define AUTHOR_EMAIL "################"
/** The OAuth2.0 access token
* The generation, exchange and refresh of the access token are not available
* in this library.
*
* To test this using GMail, get the OAuth2.0 access token from this web site
* https://developers.google.com/oauthplayground/
*
* 1. Select the following scope (in Step 1) from Gmail API V1
* https://mail.google.com/
* https://mail.google.com/
*
* 2. Click Authorize APIs button.
* 3. Cick Exchangeauthorization code for tokens.
* 4. From the response, look at access_token from the JSON payload node.
* 5. Copy that access token and paste to the AUTHOR_ACCESS_TOKEN value.
*
* The token will be expired in 3600 seconds (1 Hr).
* The AUTHOR_EMAIL above is the Email address that you granted to access the Gmail services.
*/
#define AUTHOR_ACCESS_TOKEN "################"
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status);
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(IMAPSession &imap);
/* Print all messages from the message list */
void printMessages(IMAPSession &imap);
/* Print all rfc822 messages included in the message */
void printRFC822Messages(IMAP_MSG_Item &msg);
/* Print all attachments info from the message */
void printAttacements(IMAP_MSG_Item &msg);
/* The IMAP Session object used for Email reading */
IMAPSession imap;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
imap.debug(1);
/* Set the callback function to get the reading results */
imap.callback(imapCallback);
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Declare the session config data */
ESP_Mail_Session session;
/* Set the session config */
session.server.host_name = IMAP_HOST;
session.server.port = IMAP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.accessToken = AUTHOR_ACCESS_TOKEN;
/* Setup the configuration for searching or fetching operation and its result */
IMAP_Config config;
/* Message UID to fetch or read e.g. 100 */
config.fetch.uid = "100";
/* Set seen flag*/
//config.fetch.set_seen = true;
/* Search criteria */
config.search.criteria = "";
/* Also search the unseen message */
config.search.unseen_msg = true;
/* Set the storage to save the downloaded files and attachments */
config.storage.saved_path = "/email_data";
/** The file storage type e.g.
* esp_mail_file_storage_type_none,
* esp_mail_file_storage_type_flash, and
* esp_mail_file_storage_type_sd
*/
config.storage.type = esp_mail_file_storage_type_flash;
/** Set to download heades, text and html messaeges,
* attachments and inline images respectively.
*/
config.download.header = true;
config.download.text = true;
config.download.html = true;
config.download.attachment = true;
config.download.inlineImg = true;
/** Set to enable the results i.e. html and text messaeges
* which the content stored in the IMAPSession object is limited
* by the option config.limit.msg_size.
* The whole message can be download through config.download.text
* or config.download.html which not depends on these enable options.
*/
config.enable.html = true;
config.enable.text = true;
/* Set to enable the sort the result by message UID in the ascending order */
config.enable.recent_sort = true;
/* Set to report the download progress via the default serial port */
config.enable.download_status = true;
/* Set the limit of number of messages in the search results */
config.limit.search = 5;
/** Set the maximum size of message stored in
* IMAPSession object in byte
*/
config.limit.msg_size = 512;
/** Set the maximum attachments and inline images files size
* that can be downloaded in byte.
* The file which its size is largger than this limit may be saved
* as truncated file.
*/
config.limit.attachment_size = 1024 * 1024 * 5;
/* Connect to server with the session and config */
if (!imap.connect(&session, &config))
return;
/* {Optional] */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder("INBOX"))
return;
/* {Optional] */
printSelectedMailboxInfo(imap);
/* Read or search the Email and close the session */
MailClient.readMail(&imap);
/* Clear all stored data in IMAPSession object */
imap.empty();
}
void loop()
{
}
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Show the result when reading finished */
if (status.success())
{
/* Print the result */
printMessages(imap);
/* Clear all stored data in IMAPSession object */
imap.empty();
Serial.printf("Free Heap: %d", ESP.getFreeHeap());
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
Serial.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(IMAPSession &imap)
{
/* Declare the selected folder info class to get the info of selected mailbox folder */
SelectedFolderInfo sFolder = imap.selectedFolder();
/* Show the mailbox info */
Serial.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
Serial.printf("Predicted next UID: %d\n", sFolder.nextUID());
for (size_t i = 0; i < sFolder.flagCount(); i++)
Serial.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
}
void printRFC822Messages(IMAP_MSG_Item &msg)
{
Serial.printf("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size());
for (size_t j = 0; j < msg.rfc822.size(); j++)
{
IMAP_MSG_Item rfc822 = msg.rfc822[j];
Serial.printf("%d. \n", j + 1);
Serial.printf("Messsage ID: %s\n", rfc822.messageID);
Serial.printf("From: %s\n", rfc822.from);
Serial.printf("Sender: %s\n", rfc822.sender);
Serial.printf("To: %s\n", rfc822.to);
Serial.printf("CC: %s\n", rfc822.cc);
Serial.printf("Subject: %s\n", rfc822.subject);
Serial.printf("Date: %s\n", rfc822.date);
Serial.printf("Reply-To: %s\n", rfc822.reply_to);
Serial.printf("Return-Path: %s\n", rfc822.return_path);
Serial.printf("Comment: %s\n", rfc822.comment);
Serial.printf("Keyword: %s\n", rfc822.keyword);
Serial.printf("Text Message: %s\n", rfc822.text.content);
Serial.printf("Text Message Charset: %s\n", rfc822.text.charSet);
Serial.printf("Text Message Transfer Encoding: %s\n", rfc822.text.transfer_encoding);
Serial.printf("HTML Message: %s\n", rfc822.html.content);
Serial.printf("HTML Message Charset: %s\n", rfc822.html.charSet);
Serial.printf("HTML Message Transfer Encoding: %s\n\n", rfc822.html.transfer_encoding);
if (rfc822.attachments.size() > 0)
printAttacements(rfc822);
}
}
void printAttacements(IMAP_MSG_Item &msg)
{
Serial.printf("Attachment: %d file(s)\n****************************\n", msg.attachments.size());
for (size_t j = 0; j < msg.attachments.size(); j++)
{
IMAP_Attach_Item att = msg.attachments[j];
/** att.type can be
* esp_mail_att_type_none or 0
* esp_mail_att_type_attachment or 1
* esp_mail_att_type_inline or 2
*/
Serial.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.creationDate);
}
Serial.println();
}
void printMessages(IMAPSession &imap)
{
/* Get the message list from the message list data */
IMAP_MSG_List msgList = imap.data();
for (size_t i = 0; i < msgList.msgItems.size(); i++)
{
/* Iterate to get each message data through the message item data */
IMAP_MSG_Item msg = msgList.msgItems[i];
Serial.println("################################");
Serial.printf("Messsage Number: %s\n", msg.msgNo);
Serial.printf("Messsage UID: %s\n", msg.UID);
Serial.printf("Messsage ID: %s\n", msg.ID);
Serial.printf("Accept Language: %s\n", msg.acceptLang);
Serial.printf("Content Language: %s\n", msg.contentLang);
Serial.printf("From: %s\n", msg.from);
Serial.printf("From Charset: %s\n", msg.fromCharset);
Serial.printf("To: %s\n", msg.to);
Serial.printf("To Charset: %s\n", msg.toCharset);
Serial.printf("CC: %s\n", msg.cc);
Serial.printf("CC Charset: %s\n", msg.ccCharset);
Serial.printf("Date: %s\n", msg.date);
Serial.printf("Subject: %s\n", msg.subject);
Serial.printf("Subject Charset: %s\n", msg.subjectCharset);
/* If the result contains the message info (Fetch mode) */
if (!imap.headerOnly())
{
Serial.printf("Text Message: %s\n", msg.text.content);
Serial.printf("Text Message Charset: %s\n", msg.text.charSet);
Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
Serial.printf("HTML Message: %s\n", msg.html.content);
Serial.printf("HTML Message Charset: %s\n", msg.html.charSet);
Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
if (msg.attachments.size() > 0)
printAttacements(msg);
if (msg.rfc822.size() > 0)
printRFC822Messages(msg);
}
Serial.println();
}
}

View File

@ -0,0 +1,349 @@
/**
* This example will fetch or read the Email which the known message UID
* was used for fetching.
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "################"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "################"
#define AUTHOR_PASSWORD "################"
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status);
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(IMAPSession &imap);
/* Print all messages from the message list */
void printMessages(IMAPSession &imap);
/* Print all rfc822 messages included in the message */
void printRFC822Messages(IMAP_MSG_Item &msg);
/* Print all attachments info from the message */
void printAttacements(IMAP_MSG_Item &msg);
/* The IMAP Session object used for Email reading */
IMAPSession imap;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
imap.debug(1);
/* Set the callback function to get the reading results */
imap.callback(imapCallback);
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Declare the session config data */
ESP_Mail_Session session;
/* Set the session config */
session.server.host_name = IMAP_HOST;
session.server.port = IMAP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
/* Setup the configuration for searching or fetching operation and its result */
IMAP_Config config;
/* Message UID to fetch or read e.g. 100 */
config.fetch.uid = "100";
/* Set seen flag */
//config.fetch.set_seen = true;
/* Search criteria */
config.search.criteria = "";
/* Also search the unseen message */
config.search.unseen_msg = true;
/* Set the storage to save the downloaded files and attachments */
config.storage.saved_path = "/email_data";
/** The file storage type e.g.
* esp_mail_file_storage_type_none,
* esp_mail_file_storage_type_flash, and
* esp_mail_file_storage_type_sd
*/
config.storage.type = esp_mail_file_storage_type_flash;
/** Set to download heades, text and html messaeges,
* attachments and inline images respectively.
*/
config.download.header = true;
config.download.text = true;
config.download.html = true;
config.download.attachment = true;
config.download.inlineImg = true;
/** Set to enable the results i.e. html and text messaeges
* which the content stored in the IMAPSession object is limited
* by the option config.limit.msg_size.
* The whole message can be download through config.download.text
* or config.download.html which not depends on these enable options.
*/
config.enable.html = true;
config.enable.text = true;
/* Set to enable the sort the result by message UID in the ascending order */
config.enable.recent_sort = true;
/* Set to report the download progress via the default serial port */
config.enable.download_status = true;
/* Set the limit of number of messages in the search results */
config.limit.search = 5;
/** Set the maximum size of message stored in
* IMAPSession object in byte
*/
config.limit.msg_size = 512;
/** Set the maximum attachments and inline images files size
* that can be downloaded in byte.
* The file which its size is largger than this limit may be saved
* as truncated file.
*/
config.limit.attachment_size = 1024 * 1024 * 5;
/* Connect to server with the session and config */
if (!imap.connect(&session, &config))
return;
/* {Optional] */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder("INBOX"))
return;
/* {Optional] */
printSelectedMailboxInfo(imap);
/* Read or search the Email and close the session */
MailClient.readMail(&imap);
/* Clear all stored data in IMAPSession object */
imap.empty();
}
void loop()
{
}
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Show the result when reading finished */
if (status.success())
{
/* Print the result */
printMessages(imap);
/* Clear all stored data in IMAPSession object */
imap.empty();
Serial.printf("Free Heap: %d", ESP.getFreeHeap());
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
Serial.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(IMAPSession &imap)
{
/* Declare the selected folder info class to get the info of selected mailbox folder */
SelectedFolderInfo sFolder = imap.selectedFolder();
/* Show the mailbox info */
Serial.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
Serial.printf("Predicted next UID: %d\n", sFolder.nextUID());
for (size_t i = 0; i < sFolder.flagCount(); i++)
Serial.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
}
void printRFC822Messages(IMAP_MSG_Item &msg)
{
Serial.printf("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size());
for (size_t j = 0; j < msg.rfc822.size(); j++)
{
IMAP_MSG_Item rfc822 = msg.rfc822[j];
Serial.printf("%d. \n", j + 1);
Serial.printf("Messsage ID: %s\n", rfc822.messageID);
Serial.printf("From: %s\n", rfc822.from);
Serial.printf("Sender: %s\n", rfc822.sender);
Serial.printf("To: %s\n", rfc822.to);
Serial.printf("CC: %s\n", rfc822.cc);
Serial.printf("Subject: %s\n", rfc822.subject);
Serial.printf("Date: %s\n", rfc822.date);
Serial.printf("Reply-To: %s\n", rfc822.reply_to);
Serial.printf("Return-Path: %s\n", rfc822.return_path);
Serial.printf("Comment: %s\n", rfc822.comment);
Serial.printf("Keyword: %s\n", rfc822.keyword);
Serial.printf("Text Message: %s\n", rfc822.text.content);
Serial.printf("Text Message Charset: %s\n", rfc822.text.charSet);
Serial.printf("Text Message Transfer Encoding: %s\n", rfc822.text.transfer_encoding);
Serial.printf("HTML Message: %s\n", rfc822.html.content);
Serial.printf("HTML Message Charset: %s\n", rfc822.html.charSet);
Serial.printf("HTML Message Transfer Encoding: %s\n\n", rfc822.html.transfer_encoding);
if (rfc822.attachments.size() > 0)
printAttacements(rfc822);
}
}
void printAttacements(IMAP_MSG_Item &msg)
{
Serial.printf("Attachment: %d file(s)\n****************************\n", msg.attachments.size());
for (size_t j = 0; j < msg.attachments.size(); j++)
{
IMAP_Attach_Item att = msg.attachments[j];
/** att.type can be
* esp_mail_att_type_none or 0
* esp_mail_att_type_attachment or 1
* esp_mail_att_type_inline or 2
*/
Serial.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.creationDate);
}
Serial.println();
}
void printMessages(IMAPSession &imap)
{
/* Get the message list from the message list data */
IMAP_MSG_List msgList = imap.data();
for (size_t i = 0; i < msgList.msgItems.size(); i++)
{
/* Iterate to get each message data through the message item data */
IMAP_MSG_Item msg = msgList.msgItems[i];
Serial.println("################################");
Serial.printf("Messsage Number: %s\n", msg.msgNo);
Serial.printf("Messsage UID: %s\n", msg.UID);
Serial.printf("Messsage ID: %s\n", msg.ID);
Serial.printf("Accept Language: %s\n", msg.acceptLang);
Serial.printf("Content Language: %s\n", msg.contentLang);
Serial.printf("From: %s\n", msg.from);
Serial.printf("From Charset: %s\n", msg.fromCharset);
Serial.printf("To: %s\n", msg.to);
Serial.printf("To Charset: %s\n", msg.toCharset);
Serial.printf("CC: %s\n", msg.cc);
Serial.printf("CC Charset: %s\n", msg.ccCharset);
Serial.printf("Date: %s\n", msg.date);
Serial.printf("Subject: %s\n", msg.subject);
Serial.printf("Subject Charset: %s\n", msg.subjectCharset);
/* If the result contains the message info (Fetch mode) */
if (!imap.headerOnly())
{
Serial.printf("Text Message: %s\n", msg.text.content);
Serial.printf("Text Message Charset: %s\n", msg.text.charSet);
Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
Serial.printf("HTML Message: %s\n", msg.html.content);
Serial.printf("HTML Message Charset: %s\n", msg.html.charSet);
Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
if (msg.attachments.size() > 0)
printAttacements(msg);
if (msg.rfc822.size() > 0)
printRFC822Messages(msg);
}
Serial.println();
}
}

View File

@ -0,0 +1,376 @@
/**
* This example will repeatedly fetch or read the Email via the loop function
* using the predict next message UID as the starting count down message UID.
*
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "################"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "################"
#define AUTHOR_PASSWORD "################"
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status);
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(IMAPSession &imap);
/* Print all messages from the message list */
void printMessages(IMAPSession &imap);
/* Print all rfc822 messages included in the message */
void printRFC822Messages(IMAP_MSG_Item &msg);
/* Print all attachments info from the message */
void printAttacements(IMAP_MSG_Item &msg);
/* The IMAP Session object used for Email reading */
IMAPSession imap;
unsigned long readMillis = 0;
int nextMsgUID = 0;
int msgUID = 0;
int sign = -1;
/* Declare the session config data */
ESP_Mail_Session session;
/* Setup the configuration for searching or fetching operation and its result */
IMAP_Config config;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
imap.debug(1);
/* Set the callback function to get the reading results */
imap.callback(imapCallback);
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Set the session config */
session.server.host_name = IMAP_HOST;
session.server.port = IMAP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
/* Message UID to fetch or read */
config.fetch.uid = "";
/* Search criteria */
config.search.criteria = "";
/* Also search the unseen message */
config.search.unseen_msg = true;
/* Set the storage to save the downloaded files and attachments */
config.storage.saved_path = "/email_data";
/** The file storage type e.g.
* esp_mail_file_storage_type_none,
* esp_mail_file_storage_type_flash, and
* esp_mail_file_storage_type_sd
*/
config.storage.type = esp_mail_file_storage_type_flash;
/** Set to download heades, text and html messaeges,
* attachments and inline images respectively.
*/
config.download.header = false;
config.download.text = false;
config.download.html = false;
config.download.attachment = false;
config.download.inlineImg = false;
/** Set to enable the results i.e. html and text messaeges
* which the content stored in the IMAPSession object is limited
* by the option config.limit.msg_size.
* The whole message can be download through config.download.text
* or config.download.html which not depends on these enable options.
*/
config.enable.html = true;
config.enable.text = true;
/* Set to enable the sort the result by message UID in the ascending order */
config.enable.recent_sort = true;
/* Set to report the download progress via the default serial port */
config.enable.download_status = true;
/* Set the limit of number of messages in the search results */
config.limit.search = 5;
/** Set the maximum size of message stored in
* IMAPSession object in byte
*/
config.limit.msg_size = 512;
/** Set the maximum attachments and inline images files size
* that can be downloaded in byte.
* The file which its size is largger than this limit may be saved
* as truncated file.
*/
config.limit.attachment_size = 1024 * 1024 * 5;
/* Connect to server with the session and config */
if (!imap.connect(&session, &config))
return;
/* {Optional] */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder("INBOX"))
return;
/* {Optional] */
printSelectedMailboxInfo(imap);
}
void loop()
{
if (millis() - readMillis > 10000 || readMillis == 0)
{
readMillis = millis();
if (msgUID == 0)
sign = 1;
else if (msgUID >= nextMsgUID)
sign = -1;
msgUID += sign;
String uid = String(msgUID);
/* Message UID to fetch or read */
config.fetch.uid = uid.c_str();
/* Set seen flag */
//config.fetch.set_seen = true;
/** Read or search the Email and keep the TCP session to open
* The second parameter is for close the session.
*/
MailClient.readMail(&imap, false);
/* Clear all stored data in IMAPSession object */
imap.empty();
}
}
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Show the result when reading finished */
if (status.success())
{
/* Print the result */
printMessages(imap);
/* Clear all stored data in IMAPSession object */
imap.empty();
Serial.printf("Free Heap: %d", ESP.getFreeHeap());
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
Serial.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(IMAPSession &imap)
{
/* Declare the selected folder info class to get the info of selected mailbox folder */
SelectedFolderInfo sFolder = imap.selectedFolder();
nextMsgUID = sFolder.nextUID();
msgUID = nextMsgUID;
/* Show the mailbox info */
Serial.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
Serial.printf("Predicted next UID: %d\n", sFolder.nextUID());
for (size_t i = 0; i < sFolder.flagCount(); i++)
Serial.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
}
void printRFC822Messages(IMAP_MSG_Item &msg)
{
Serial.printf("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size());
for (size_t j = 0; j < msg.rfc822.size(); j++)
{
IMAP_MSG_Item rfc822 = msg.rfc822[j];
Serial.printf("%d. \n", j + 1);
Serial.printf("Messsage ID: %s\n", rfc822.messageID);
Serial.printf("From: %s\n", rfc822.from);
Serial.printf("Sender: %s\n", rfc822.sender);
Serial.printf("To: %s\n", rfc822.to);
Serial.printf("CC: %s\n", rfc822.cc);
Serial.printf("Subject: %s\n", rfc822.subject);
Serial.printf("Date: %s\n", rfc822.date);
Serial.printf("Reply-To: %s\n", rfc822.reply_to);
Serial.printf("Return-Path: %s\n", rfc822.return_path);
Serial.printf("Comment: %s\n", rfc822.comment);
Serial.printf("Keyword: %s\n", rfc822.keyword);
Serial.printf("Text Message: %s\n", rfc822.text.content);
Serial.printf("Text Message Charset: %s\n", rfc822.text.charSet);
Serial.printf("Text Message Transfer Encoding: %s\n", rfc822.text.transfer_encoding);
Serial.printf("HTML Message: %s\n", rfc822.html.content);
Serial.printf("HTML Message Charset: %s\n", rfc822.html.charSet);
Serial.printf("HTML Message Transfer Encoding: %s\n\n", rfc822.html.transfer_encoding);
if (rfc822.attachments.size() > 0)
printAttacements(rfc822);
}
}
void printAttacements(IMAP_MSG_Item &msg)
{
Serial.printf("Attachment: %d file(s)\n****************************\n", msg.attachments.size());
for (size_t j = 0; j < msg.attachments.size(); j++)
{
IMAP_Attach_Item att = msg.attachments[j];
/** att.type can be
* esp_mail_att_type_none or 0
* esp_mail_att_type_attachment or 1
* esp_mail_att_type_inline or 2
*/
Serial.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.creationDate);
}
Serial.println();
}
void printMessages(IMAPSession &imap)
{
/* Get the message list from the message list data */
IMAP_MSG_List msgList = imap.data();
for (size_t i = 0; i < msgList.msgItems.size(); i++)
{
/* Iterate to get each message data through the message item data */
IMAP_MSG_Item msg = msgList.msgItems[i];
Serial.println("################################");
Serial.printf("Messsage Number: %s\n", msg.msgNo);
Serial.printf("Messsage UID: %s\n", msg.UID);
Serial.printf("Messsage ID: %s\n", msg.ID);
Serial.printf("Accept Language: %s\n", msg.acceptLang);
Serial.printf("Content Language: %s\n", msg.contentLang);
Serial.printf("From: %s\n", msg.from);
Serial.printf("From Charset: %s\n", msg.fromCharset);
Serial.printf("To: %s\n", msg.to);
Serial.printf("To Charset: %s\n", msg.toCharset);
Serial.printf("CC: %s\n", msg.cc);
Serial.printf("CC Charset: %s\n", msg.ccCharset);
Serial.printf("Date: %s\n", msg.date);
Serial.printf("Subject: %s\n", msg.subject);
Serial.printf("Subject Charset: %s\n", msg.subjectCharset);
/* If the result contains the message info (Fetch mode) */
if (!imap.headerOnly())
{
Serial.printf("Text Message: %s\n", msg.text.content);
Serial.printf("Text Message Charset: %s\n", msg.text.charSet);
Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
Serial.printf("HTML Message: %s\n", msg.html.content);
Serial.printf("HTML Message Charset: %s\n", msg.html.charSet);
Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
if (msg.attachments.size() > 0)
printAttacements(msg);
if (msg.rfc822.size() > 0)
printRFC822Messages(msg);
}
Serial.println();
}
}

View File

@ -0,0 +1,387 @@
/**
* This example will search all Emails in the opened mailbox folder.
*
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "################"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "################"
#define AUTHOR_PASSWORD "################"
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status);
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(IMAPSession &imap);
/* Print all messages from the message list */
void printMessages(IMAPSession &imap);
/* Print all rfc822 messages included in the message */
void printRFC822Messages(IMAP_MSG_Item &msg);
/* Print all attachments info from the message */
void printAttacements(IMAP_MSG_Item &msg);
/* The IMAP Session object used for Email reading */
IMAPSession imap;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
imap.debug(1);
/* Set the callback function to get the reading results */
imap.callback(imapCallback);
/* Declare the session config data */
ESP_Mail_Session session;
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Set the session config */
session.server.host_name = IMAP_HOST;
session.server.port = IMAP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
/* Setup the configuration for searching or fetching operation and its result */
IMAP_Config config;
/* Message UID to fetch or read */
config.fetch.uid = "";
/** Search criteria
*
* A search key can also be a parenthesized list of one or more search keys
* (e.g., for use with the OR and NOT keys).
*
* Since IMAP protocol uses Polish notation, the search criteria which in the polish notation form can be.
*
* To search the message from "someone@email.com" with the subject "my subject" since 1 Jan 2021, your search criteria can be
* UID SEARCH (OR SUBJECT "my subject" FROM "someone@email.com") SINCE "Fri, 1 Jan 2021 21:52:25 -0800"
*
* To search the message from "mail1@domain.com" or from "mail2@domain.com", the search criteria will be
* UID SEARCH OR FROM mail1@domain.com FROM mail2@domain.com
*
* For more details on using parentheses, AND, OR and NOT search keys in search criteria.
* https://www.limilabs.com/blog/imap-search-requires-parentheses
*
*
*/
config.search.criteria = "UID SEARCH ALL";
/* Also search the unseen message */
config.search.unseen_msg = true;
/* Set the storage to save the downloaded files and attachments */
config.storage.saved_path = "/email_data";
/** The file storage type e.g.
* esp_mail_file_storage_type_none,
* esp_mail_file_storage_type_flash, and
* esp_mail_file_storage_type_sd
*/
config.storage.type = esp_mail_file_storage_type_flash;
/** Set to download heades, text and html messaeges,
* attachments and inline images respectively.
*/
config.download.header = true;
config.download.text = true;
config.download.html = true;
config.download.attachment = true;
config.download.inlineImg = true;
/** Set to enable the results i.e. html and text messaeges
* which the content stored in the IMAPSession object is limited
* by the option config.limit.msg_size.
* The whole message can be download through config.download.text
* or config.download.html which not depends on these enable options.
*/
config.enable.html = true;
config.enable.text = true;
/* Set to enable the sort the result by message UID in the ascending order */
config.enable.recent_sort = true;
/* Set to report the download progress via the default serial port */
config.enable.download_status = true;
/* Set the limit of number of messages in the search results */
config.limit.search = 5;
/** Set the maximum size of message stored in
* IMAPSession object in byte
*/
config.limit.msg_size = 512;
/** Set the maximum attachments and inline images files size
* that can be downloaded in byte.
* The file which its size is largger than this limit may be saved
* as truncated file.
*/
config.limit.attachment_size = 1024 * 1024 * 5;
/* Connect to server with the session and config */
if (!imap.connect(&session, &config))
return;
/* {Optional] */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder("INBOX"))
return;
/* {Optional] */
printSelectedMailboxInfo(imap);
/** Read or search the Email and keep the TCP session to open
* The second parameter is for close the session.
*/
MailClient.readMail(&imap, false);
/* Clear all stored data in IMAPSession object */
imap.empty();
/** Open or select other mailbox folder
* The folder that previousely opened will be closed
*/
if (imap.selectFolder("Junk"))
{
/* {Optional] */
printSelectedMailboxInfo(imap);
/* Config to search all messages in the opened mailboax (Search mode) */
config.search.criteria = "UID SEARCH ALL";
/* No message UID provide for fetching */
config.fetch.uid = "";
/* Search the Email and close the session */
MailClient.readMail(&imap);
}
/* Close the seeion in case the session is still open */
imap.closeSession();
/* Clear all stored data in IMAPSession object */
imap.empty();
}
void loop()
{
}
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Show the result when reading finished */
if (status.success())
{
/* Print the result */
printMessages(imap);
/* Clear all stored data in IMAPSession object */
imap.empty();
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
Serial.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(IMAPSession &imap)
{
/* Declare the selected folder info class to get the info of selected mailbox folder */
SelectedFolderInfo sFolder = imap.selectedFolder();
/* Show the mailbox info */
Serial.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
Serial.printf("Predicted next UID: %d\n", sFolder.nextUID());
for (size_t i = 0; i < sFolder.flagCount(); i++)
Serial.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
}
void printRFC822Messages(IMAP_MSG_Item &msg)
{
Serial.printf("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size());
for (size_t j = 0; j < msg.rfc822.size(); j++)
{
IMAP_MSG_Item rfc822 = msg.rfc822[j];
Serial.printf("%d. \n", j + 1);
Serial.printf("Messsage ID: %s\n", rfc822.messageID);
Serial.printf("From: %s\n", rfc822.from);
Serial.printf("Sender: %s\n", rfc822.sender);
Serial.printf("To: %s\n", rfc822.to);
Serial.printf("CC: %s\n", rfc822.cc);
Serial.printf("Subject: %s\n", rfc822.subject);
Serial.printf("Date: %s\n", rfc822.date);
Serial.printf("Reply-To: %s\n", rfc822.reply_to);
Serial.printf("Return-Path: %s\n", rfc822.return_path);
Serial.printf("Comment: %s\n", rfc822.comment);
Serial.printf("Keyword: %s\n", rfc822.keyword);
Serial.printf("Text Message: %s\n", rfc822.text.content);
Serial.printf("Text Message Charset: %s\n", rfc822.text.charSet);
Serial.printf("Text Message Transfer Encoding: %s\n", rfc822.text.transfer_encoding);
Serial.printf("HTML Message: %s\n", rfc822.html.content);
Serial.printf("HTML Message Charset: %s\n", rfc822.html.charSet);
Serial.printf("HTML Message Transfer Encoding: %s\n\n", rfc822.html.transfer_encoding);
if (rfc822.attachments.size() > 0)
printAttacements(rfc822);
}
}
void printAttacements(IMAP_MSG_Item &msg)
{
Serial.printf("Attachment: %d file(s)\n****************************\n", msg.attachments.size());
for (size_t j = 0; j < msg.attachments.size(); j++)
{
IMAP_Attach_Item att = msg.attachments[j];
/** att.type can be
* esp_mail_att_type_none or 0
* esp_mail_att_type_attachment or 1
* esp_mail_att_type_inline or 2
*/
Serial.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.creationDate);
}
Serial.println();
}
void printMessages(IMAPSession &imap)
{
/* Get the message list from the message list data */
IMAP_MSG_List msgList = imap.data();
for (size_t i = 0; i < msgList.msgItems.size(); i++)
{
/* Iterate to get each message data through the message item data */
IMAP_MSG_Item msg = msgList.msgItems[i];
Serial.println("################################");
Serial.printf("Messsage Number: %s\n", msg.msgNo);
Serial.printf("Messsage UID: %s\n", msg.UID);
Serial.printf("Messsage ID: %s\n", msg.ID);
Serial.printf("Accept Language: %s\n", msg.acceptLang);
Serial.printf("Content Language: %s\n", msg.contentLang);
Serial.printf("From: %s\n", msg.from);
Serial.printf("From Charset: %s\n", msg.fromCharset);
Serial.printf("To: %s\n", msg.to);
Serial.printf("To Charset: %s\n", msg.toCharset);
Serial.printf("CC: %s\n", msg.cc);
Serial.printf("CC Charset: %s\n", msg.ccCharset);
Serial.printf("Date: %s\n", msg.date);
Serial.printf("Subject: %s\n", msg.subject);
Serial.printf("Subject Charset: %s\n", msg.subjectCharset);
/* If the result contains the message info (Fetch mode) */
if (!imap.headerOnly())
{
Serial.printf("Text Message: %s\n", msg.text.content);
Serial.printf("Text Message Charset: %s\n", msg.text.charSet);
Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
Serial.printf("HTML Message: %s\n", msg.html.content);
Serial.printf("HTML Message Charset: %s\n", msg.html.charSet);
Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
if (msg.attachments.size() > 0)
printAttacements(msg);
if (msg.rfc822.size() > 0)
printRFC822Messages(msg);
}
Serial.println();
}
}

View File

@ -0,0 +1,200 @@
/**
*This example will log in with the SASL XOAUTH2 mechanisme using OAuth2.0 access token.
*
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
#define SMTP_HOST "################"
/** The smtp port e.g.
* 25 or esp_mail_smtp_port_25
* 465 or esp_mail_smtp_port_465
* 587 or esp_mail_smtp_port_587
*/
#define SMTP_PORT 25
/* The user Email for OAuth2.0 access token */
#define AUTHOR_EMAIL "################"
/** The OAuth2.0 access token
* The generation, exchange and refresh of the access token are not available
* in this library.
*
* To test this using GMail, get the OAuth2.0 access token from this web site
* https://developers.google.com/oauthplayground/
*
* 1. Select the following scope (in Step 1) from Gmail API V1
* https://mail.google.com/
* https://mail.google.com/
*
* 2. Click Authorize APIs button.
* 3. Cick Exchangeauthorization code for tokens.
* 4. From the response, look at access_token from the JSON payload node.
* 5. Copy that access token and paste to the AUTHOR_ACCESS_TOKEN value.
*
* The token will be expired in 3600 seconds (1 Hr).
* The AUTHOR_EMAIL above is the Email address that you granted to access the Gmail services.
*/
#define AUTHOR_ACCESS_TOKEN "################"
/* The SMTP Session object used for Email sending */
SMTPSession smtp;
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
smtp.debug(1);
/* Set the callback function to get the sending results */
smtp.callback(smtpCallback);
/* Declare the session config data */
ESP_Mail_Session session;
/* Set the session config */
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.accessToken = AUTHOR_ACCESS_TOKEN;
session.login.user_domain = "mydomain.net";
/* Declare the message class */
SMTP_Message message;
/* Set the message headers */
message.sender.name = "ESP Mail";
message.sender.email = AUTHOR_EMAIL;
message.subject = "Test sending Email using Access token";
message.addRecipient("Admin", "####@#####_dot_com");
message.text.content = "This is simple plain text message";
/** The Plain text message character set e.g.
* us-ascii
* utf-8
* utf-7
* The default value is utf-8
*/
message.text.charSet = "us-ascii";
/** The content transfer encoding e.g.
* enc_7bit or "7bit" (not encoded)
* enc_qp or "quoted-printable" (encoded)
* enc_base64 or "base64" (encoded)
* enc_binary or "binary" (not encoded)
* enc_8bit or "8bit" (not encoded)
* The default value is "7bit"
*/
message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit;
/** The message priority
* esp_mail_smtp_priority_high or 1
* esp_mail_smtp_priority_normal or 3
* esp_mail_smtp_priority_low or 5
* The default value is esp_mail_smtp_priority_low
*/
message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low;
/** The Delivery Status Notifications e.g.
* esp_mail_smtp_notify_never
* esp_mail_smtp_notify_success
* esp_mail_smtp_notify_failure
* esp_mail_smtp_notify_delay
* The default value is esp_mail_smtp_notify_never
*/
message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay;
/* Connect to server with the session config */
if (!smtp.connect(&session))
return;
/* Set the custom message header */
message.addHeader("Message-ID: <abcde.fghij@gmail.com>");
/* Start sending Email and close the session */
if (!MailClient.sendMail(&smtp, &message))
Serial.println("Error sending Email, " + smtp.errorReason());
}
void loop()
{
}
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Print the sending result */
if (status.success())
{
Serial.println("----------------");
Serial.printf("Message sent success: %d\n", status.completedCount());
Serial.printf("Message sent failled: %d\n", status.failedCount());
Serial.println("----------------\n");
struct tm dt;
for (size_t i = 0; i < smtp.sendingResult.size(); i++)
{
/* Get the result item */
SMTP_Result result = smtp.sendingResult.getItem(i);
localtime_r(&result.timesstamp, &dt);
Serial.printf("Message No: %d\n", i + 1);
Serial.printf("Status: %s\n", result.completed ? "success" : "failed");
Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec);
Serial.printf("Recipient: %s\n", result.recipients);
Serial.printf("Subject: %s\n", result.subject);
}
Serial.println("----------------\n");
}
}

View File

@ -0,0 +1,268 @@
/**
* This example will send the Email with attachments and
* inline images stored in heap and flash memories.
*
* The html and text version messages will be sent.
*
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
/* This is for attachment data */
#include "image.h"
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com
* For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
* and use the app password as password with your yahoo mail account to login.
* The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en
*/
#define SMTP_HOST "################"
/** The smtp port e.g.
* 25 or esp_mail_smtp_port_25
* 465 or esp_mail_smtp_port_465
* 587 or esp_mail_smtp_port_587
*/
#define SMTP_PORT esp_mail_smtp_port_587
/* The log in credentials */
#define AUTHOR_EMAIL "################"
#define AUTHOR_PASSWORD "################"
/* The SMTP Session object used for Email sending */
SMTPSession smtp;
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
smtp.debug(1);
/* Set the callback function to get the sending results */
smtp.callback(smtpCallback);
/* Declare the session config data */
ESP_Mail_Session session;
/* Set the session config */
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
session.login.user_domain = "mydomain.net";
/* Declare the message class */
SMTP_Message message;
/* Enable the chunked data transfer with pipelining for large message if server supported */
message.enable.chunking = true;
/* Set the message headers */
message.sender.name = "ESP Mail";
message.sender.email = AUTHOR_EMAIL;
message.subject = "Test sending Email with attachments and inline images";
message.addRecipient("user1", "####@#####_dot_com");
message.html.content = "<span style=\"color:#ff0000;\">This message contains 3 inline images and 1 attachment file.</span><br/><br/><img src=\"firebase_logo.png\" width=\"80\" height=\"60\"> <img src=\"tree.gif\" width=\"40\" height=\"60\"> <img src=\"bird.gif\" width=\"116\" height=\"75\">";
/** The HTML text message character set e.g.
* us-ascii
* utf-8
* utf-7
* The default value is utf-8
*/
message.html.charSet = "utf-8";
/** The content transfer encoding e.g.
* enc_7bit or "7bit" (not encoded)
* enc_qp or "quoted-printable" (encoded)
* enc_base64 or "base64" (encoded)
* enc_binary or "binary" (not encoded)
* enc_8bit or "8bit" (not encoded)
* The default value is "7bit"
*/
message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp;
message.text.content = "This message contains 3 inline images and 1 attachment file.\r\nThe inline images were not shown in the plain text message.";
message.text.charSet = "utf-8";
message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64;
/** The message priority
* esp_mail_smtp_priority_high or 1
* esp_mail_smtp_priority_normal or 3
* esp_mail_smtp_priority_low or 5
* The default value is esp_mail_smtp_priority_low
*/
message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal;
/** The Delivery Status Notifications e.g.
* esp_mail_smtp_notify_never
* esp_mail_smtp_notify_success
* esp_mail_smtp_notify_failure
* esp_mail_smtp_notify_delay
* The default value is esp_mail_smtp_notify_never
*/
message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay;
/* Set the custom message header */
message.addHeader("Message-ID: <user1@gmail.com>");
/* The attachment data item */
SMTP_Attachment att;
/** Set the inline image info e.g.
* file name, MIME type, BLOB data, BLOB data size,
* transfer encoding (should be base64 for inline image)
*/
att.descr.filename = "firebase_logo.png";
att.descr.mime = "image/png";
att.blob.data = firebase_png;
att.blob.size = sizeof(firebase_png);
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;
/* Add inline image to the message */
message.addInlineImage(att);
/** Set the inline image info e.g.
* file name, MIME type, BLOB data, BLOB data size.
* The default transfer encoding is base64.
*/
message.resetAttachItem(att); //Clear the attach item data to reuse
att.descr.filename = "tree.gif";
att.descr.mime = "image/gif";
att.blob.data = tree_gif;
att.blob.size = sizeof(tree_gif);
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;
/* Add inline image to the message */
message.addInlineImage(att);
/** Set the inline image info e.g.
* file name, MIME type, BLOB data, BLOB data size.
* The default transfer encoding is base64.
*/
message.resetAttachItem(att); //Clear the attach item data to reuse
att.descr.filename = "bird.gif";
att.descr.mime = "image/gif";
att.blob.data = bird_gif;
att.blob.size = sizeof(bird_gif);
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;
/* Add inline image to the message */
message.addInlineImage(att);
/* Prepare the attachment data (from ram) */
uint8_t *a = new uint8_t[512];
int j = 0;
for (int i = 0; i < 512; i++)
{
a[i] = j;
j++;
if (j > 255)
j = 0;
}
/** Set the attachment info e.g.
* file name, MIME type, BLOB data, BLOB data size.
* The default transfer encoding is base64.
*/
message.resetAttachItem(att); //Clear the attach item data to reuse
att.descr.filename = "test.dat";
att.descr.mime = "application/octet-stream";
att.blob.data = a;
att.blob.size = 512;
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;
/* Add attachment to the message */
message.addAttachment(att);
/* Connect to server with the session config */
if (!smtp.connect(&session))
return;
/* Start sending the Email and close the session */
if (!MailClient.sendMail(&smtp, &message, true))
Serial.println("Error sending Email, " + smtp.errorReason());
}
void loop()
{
}
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Print the sending result */
if (status.success())
{
Serial.println("----------------");
Serial.printf("Message sent success: %d\n", status.completedCount());
Serial.printf("Message sent failled: %d\n", status.failedCount());
Serial.println("----------------\n");
struct tm dt;
for (size_t i = 0; i < smtp.sendingResult.size(); i++)
{
/* Get the result item */
SMTP_Result result = smtp.sendingResult.getItem(i);
localtime_r(&result.timesstamp, &dt);
Serial.printf("Message No: %d\n", i + 1);
Serial.printf("Status: %s\n", result.completed ? "success" : "failed");
Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec);
Serial.printf("Recipient: %s\n", result.recipients);
Serial.printf("Subject: %s\n", result.subject);
}
Serial.println("----------------\n");
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,391 @@
/**
* This example will send the Email with attachments and
* inline images stored in flash and SD card.
*
* The html and text version messages will be sent.
*
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com
* For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
* and use the app password as password with your yahoo mail account to login.
* The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en
*/
#define SMTP_HOST "################"
/** The smtp port e.g.
* 25 or esp_mail_smtp_port_25
* 465 or esp_mail_smtp_port_465
* 587 or esp_mail_smtp_port_587
*/
#define SMTP_PORT esp_mail_smtp_port_587
/* The log in credentials */
#define AUTHOR_EMAIL "################"
#define AUTHOR_PASSWORD "################"
/* The SMTP Session object used for Email sending */
SMTPSession smtp;
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
static uint8_t buf[512];
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
Serial.println("Mounting SD Card...");
#if defined(ESP32)
if (SD.begin()) // MailClient.sdBegin(14,2,15,13) for TTGO T8 v1.7 or 1.8
#elif defined(ESP8266)
if (SD.begin(15))
#endif
{
if (SD.exists("/orange.png"))
SD.remove("/orange.png");
if (SD.exists("/bin1.dat"))
SD.remove("/bin1.dat");
Serial.println("Preparing SD file attachments...");
const char *orangeImg = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAoUlEQVR42u3RMQ0AMAgAsCFgftHLiQpsENJaaFT+fqwRQoQgRAhChCBECEKECBGCECEIEYIQIQgRghCECEGIEIQIQYgQhCBECEKEIEQIQoQgBCFCECIEIUIQIgQhCBGCECEIEYIQIQhBiBCECEGIEIQIQQhChCBECEKEIEQIQhAiBCFCECIEIUIQghAhCBGCECEIEYIQIUKEIEQIQoQg5LoBGi/oCaOpTXoAAAAASUVORK5CYII=";
File file = SD.open("/orange.png", FILE_WRITE);
file.print(orangeImg);
file.close();
file = SD.open("/bin1.dat", FILE_WRITE);
buf[0] = 'H';
buf[1] = 'E';
buf[2] = 'A';
buf[3] = 'D';
file.write(buf, 4);
size_t i;
for (i = 0; i < 4; i++)
{
memset(buf, i + 1, 512);
file.write(buf, 512);
}
buf[0] = 'T';
buf[1] = 'A';
buf[2] = 'I';
buf[3] = 'L';
file.write(buf, 4);
file.close();
}
else
{
Serial.println("SD Card Monting Failed");
}
Serial.println("Mounting SPIFFS...");
#if defined(ESP32)
if (SPIFFS.begin(true))
#elif defined(ESP8266)
if (SPIFFS.begin())
#endif
{
//SPIFFS.format();
if (SPIFFS.exists("/green.png"))
SPIFFS.remove("/green.png");
if (SPIFFS.exists("/bin2.dat"))
SPIFFS.remove("/bin2.dat");
Serial.println("Preparing SPIFFS attachments...");
const char *greenImg = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAoUlEQVR42u3RAQ0AMAgAoJviyWxtAtNYwzmoQGT/eqwRQoQgRAhChCBECEKECBGCECEIEYIQIQgRghCECEGIEIQIQYgQhCBECEKEIEQIQoQgBCFCECIEIUIQIgQhCBGCECEIEYIQIQhBiBCECEGIEIQIQQhChCBECEKEIEQIQhAiBCFCECIEIUIQghAhCBGCECEIEYIQIUKEIEQIQoQg5LoBBaDPbQYiMoMAAAAASUVORK5CYII=";
#if defined(ESP32)
File file = SPIFFS.open("/green.png", FILE_WRITE);
#elif defined(ESP8266)
File file = SPIFFS.open("/green.png", "w");
#endif
file.print(greenImg);
file.close();
#if defined(ESP32)
file = SPIFFS.open("/bin2.dat", FILE_WRITE);
#elif defined(ESP8266)
file = SPIFFS.open("/bin2.dat", "w");
#endif
buf[0] = 'H';
buf[1] = 'E';
buf[2] = 'L';
buf[3] = 'L';
buf[4] = 'O';
file.write(buf, 5);
size_t i;
for (i = 0; i < 4; i++)
{
memset(buf, i + 1, 512);
file.write(buf, 512);
}
buf[0] = 'G';
buf[1] = 'O';
buf[2] = 'O';
buf[3] = 'D';
buf[4] = 'B';
buf[5] = 'Y';
buf[6] = 'E';
file.write(buf, 7);
file.close();
}
else
{
Serial.println("SPIFFS Monting Failed");
}
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
smtp.debug(1);
/* Set the callback function to get the sending results */
smtp.callback(smtpCallback);
/* Declare the session config data */
ESP_Mail_Session session;
/* Set the session config */
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
session.login.user_domain = "mydomain.net";
/* Declare the message class */
SMTP_Message message;
/* Enable the chunked data transfer with pipelining for large message if server supported */
message.enable.chunking = true;
/* Set the message headers */
message.sender.name = "ESP Mail";
message.sender.email = AUTHOR_EMAIL;
message.subject = "Test sending Email with attachments and inline images from SD card and Flash";
message.addRecipient("user1", "####@#####_dot_com");
/** Two alternative content versions are sending in this example e.g. plain text and html */
message.html.content = "<span style=\"color:#ff0000;\">This message contains 2 inline images and 2 attachment files.</span><br/><br/><img src=\"green.png\" width=\"100\" height=\"100\"> <img src=\"orange.png\" width=\"100\" height=\"100\">";
/** The HTML text message character set e.g.
* us-ascii
* utf-8
* utf-7
* The default value is utf-8
*/
message.html.charSet = "utf-8";
/** The content transfer encoding e.g.
* enc_7bit or "7bit" (not encoded)
* enc_qp or "quoted-printable" (encoded)
* enc_base64 or "base64" (encoded)
* enc_binary or "binary" (not encoded)
* enc_8bit or "8bit" (not encoded)
* The default value is "7bit"
*/
message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp;
message.text.content = "This message contains 2 inline images and 2 attachment files.\r\nThe inline images were not shown in the plain text message.";
message.text.charSet = "utf-8";
message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64;
/** The message priority
* esp_mail_smtp_priority_high or 1
* esp_mail_smtp_priority_normal or 3
* esp_mail_smtp_priority_low or 5
* The default value is esp_mail_smtp_priority_low
*/
message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal;
/** The Delivery Status Notifications e.g.
* esp_mail_smtp_notify_never
* esp_mail_smtp_notify_success
* esp_mail_smtp_notify_failure
* esp_mail_smtp_notify_delay
* The default value is esp_mail_smtp_notify_never
*/
message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay;
/* Set the custom message header */
message.addHeader("Message-ID: <user1@gmail.com>");
/* The attachment data item */
SMTP_Attachment att;
/** Set the inline image info e.g.
* file name, MIME type, file path, file storage type,
* transfer encoding and content encoding
*/
att.descr.filename = "orange.png";
att.descr.mime = "image/png";
att.file.path = "/orange.png";
/** The file storage type e.g.
* esp_mail_file_storage_type_none,
* esp_mail_file_storage_type_flash, and
* esp_mail_file_storage_type_sd
*/
att.file.storage_type = esp_mail_file_storage_type_sd;
/* Need to be base64 transfer encoding for inline image */
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;
/** The orange.png file is already base64 encoded file.
* Then set the content encoding to match the transfer encoding
* which no encoding was taken place prior to sending.
*/
att.descr.content_encoding = Content_Transfer_Encoding::enc_base64;
/* Add inline image to the message */
message.addInlineImage(att);
/** Set the attachment info e.g.
* file name, MIME type, file path, file storage type,
* transfer encoding and content encoding
*/
message.resetAttachItem(att); //Clear the attach item data to reuse
att.descr.filename = "bin1.dat";
att.descr.mime = "application/octet-stream"; //binary data
att.file.path = "/bin1.dat";
att.file.storage_type = esp_mail_file_storage_type_sd;
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;
/* Add attachment to the message */
message.addAttachment(att);
/** Set the inline image info e.g.
* file name, MIME type, file path, file storage type,
* transfer encoding and content encoding
*/
message.resetAttachItem(att); //Clear the attach item data to reuse
att.descr.filename = "green.png";
att.descr.mime = "image/png";
att.file.path = "/green.png";
att.file.storage_type = esp_mail_file_storage_type_flash;
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;
att.descr.content_encoding = Content_Transfer_Encoding::enc_base64;
message.addInlineImage(att);
/** Set the attachment info e.g.
* file name, MIME type, file path, file storage type,
* transfer encoding and content encoding
*/
message.resetAttachItem(att); //Clear the attach item data to reuse
att.descr.filename = "bin2.dat";
att.descr.mime = "application/octet-stream";
att.file.path = "/bin2.dat";
att.file.storage_type = esp_mail_file_storage_type_flash;
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;
message.addAttachment(att);
/* Connect to server with the session config */
if (!smtp.connect(&session))
return;
/* Start sending the Email and close the session */
if (!MailClient.sendMail(&smtp, &message, true))
Serial.println("Error sending Email, " + smtp.errorReason());
}
void loop()
{
}
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Print the sending result */
if (status.success())
{
Serial.println("----------------");
Serial.printf("Message sent success: %d\n", status.completedCount());
Serial.printf("Message sent failled: %d\n", status.failedCount());
Serial.println("----------------\n");
struct tm dt;
for (size_t i = 0; i < smtp.sendingResult.size(); i++)
{
/* Get the result item */
SMTP_Result result = smtp.sendingResult.getItem(i);
localtime_r(&result.timesstamp, &dt);
Serial.printf("Message No: %d\n", i + 1);
Serial.printf("Status: %s\n", result.completed ? "success" : "failed");
Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec);
Serial.printf("Recipient: %s\n", result.recipients);
Serial.printf("Subject: %s\n", result.subject);
}
Serial.println("----------------\n");
}
}

View File

@ -0,0 +1,203 @@
/**
* This example will send the Email which the
* message html and text body will be embedded as
* attachment or inline content.
*
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com
* For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
* and use the app password as password with your yahoo mail account to login.
* The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en
*/
#define SMTP_HOST "################"
/** The smtp port e.g.
* 25 or esp_mail_smtp_port_25
* 465 or esp_mail_smtp_port_465
* 587 or esp_mail_smtp_port_587
*/
#define SMTP_PORT 25
/* The log in credentials */
#define AUTHOR_EMAIL "################"
#define AUTHOR_PASSWORD "################"
/* The SMTP Session object used for Email sending */
SMTPSession smtp;
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
smtp.debug(1);
/* Set the callback function to get the sending results */
smtp.callback(smtpCallback);
/* Declare the session config data */
ESP_Mail_Session session;
/* Set the session config */
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
session.login.user_domain = "mydomain.net";
/* Declare the message class */
SMTP_Message message;
/* Set the message headers */
message.sender.name = "ESP Mail";
message.sender.email = AUTHOR_EMAIL;
message.subject = "Test sending message as embedded files";
message.addRecipient("Admin", "####@#####_dot_com");
message.html.content = "<span style=\"color:#0055ff;\">This is html message</span>";
/** The Plain text message character set e.g.
* us-ascii
* utf-8
* utf-7
* The default value is utf-8
*/
message.html.charSet = "utf-8";
/** The content transfer encoding e.g.
* enc_7bit or "7bit" (not encoded)
* enc_qp or "quoted-printable" (encoded)
* enc_base64 or "base64" (encoded)
* enc_binary or "binary" (not encoded)
* enc_8bit or "8bit" (not encoded)
* The default value is "7bit"
*/
message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp;
/* Enable to send this message body as file */
message.html.embed.enable = true;
/* The name of embedded file */
message.html.embed.filename = "test.html";
/** The embedded type
* esp_mail_smtp_embed_message_type_attachment or 0
* esp_mail_smtp_embed_message_type_inline or 1
*/
message.html.embed.type = esp_mail_smtp_embed_message_type_attachment;
message.text.content = "This is simple plain text message";
message.text.charSet = "utf-8";
message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64;
message.text.embed.enable = true;
message.text.embed.filename = "test.txt";
message.text.embed.type = esp_mail_smtp_embed_message_type_inline;
/** The message priority
* esp_mail_smtp_priority_high or 1
* esp_mail_smtp_priority_normal or 3
* esp_mail_smtp_priority_low or 5
* The default value is esp_mail_smtp_priority_low
*/
message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low;
/* Set the custom message header */
message.addHeader("Message-ID: <abcde.fghij@gmail.com>");
/* Connect to server with the session config */
if (!smtp.connect(&session))
return;
/* Start sending Email and close the session */
if (!MailClient.sendMail(&smtp, &message))
Serial.println("Error sending Email, " + smtp.errorReason());
}
void loop()
{
}
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Print the sending result */
if (status.success())
{
Serial.println("----------------");
Serial.printf("Message sent success: %d\n", status.completedCount());
Serial.printf("Message sent failled: %d\n", status.failedCount());
Serial.println("----------------\n");
struct tm dt;
for (size_t i = 0; i < smtp.sendingResult.size(); i++)
{
/* Get the result item */
SMTP_Result result = smtp.sendingResult.getItem(i);
localtime_r(&result.timesstamp, &dt);
Serial.printf("Message No: %d\n", i + 1);
Serial.printf("Status: %s\n", result.completed ? "success" : "failed");
Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec);
Serial.printf("Recipient: %s\n", result.recipients);
Serial.printf("Subject: %s\n", result.subject);
}
Serial.println("----------------\n");
}
}

View File

@ -0,0 +1,187 @@
/**
* This example will send the Email in enriched text version.
*
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com
* For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
* and use the app password as password with your yahoo mail account to login.
* The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en
*/
#define SMTP_HOST "################"
/** The smtp port e.g.
* 25 or esp_mail_smtp_port_25
* 465 or esp_mail_smtp_port_465
* 587 or esp_mail_smtp_port_587
*/
#define SMTP_PORT 25
/* The log in credentials */
#define AUTHOR_EMAIL "################"
#define AUTHOR_PASSWORD "################"
/* The SMTP Session object used for Email sending */
SMTPSession smtp;
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
smtp.debug(1);
/* Set the callback function to get the sending results */
smtp.callback(smtpCallback);
/* Declare the session config data */
ESP_Mail_Session session;
/* Set the session config */
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
session.login.user_domain = "mydomain.net";
/* Declare the message class */
SMTP_Message message;
/* Set the message headers */
message.sender.name = "ESP Mail";
message.sender.email = AUTHOR_EMAIL;
message.subject = "Test sending enriched text Email";
message.addRecipient("Someone", "####@#####_dot_com");
message.text.content = "This is <bold><italic>enriched </italic></bold> <smaller>as defined in RFC 1896</smaller>\r\n\r\nIsn't it <bigger><bigger>cool?</bigger></bigger>";
message.text.content_type = "text/enriched";
/** The Plain text message character set e.g.
* us-ascii
* utf-8
* utf-7
* The default value is utf-8
*/
message.text.charSet = "us-ascii";
/** The content transfer encoding e.g.
* enc_7bit or "7bit" (not encoded)
* enc_qp or "quoted-printable" (encoded)
* enc_base64 or "base64" (encoded)
* enc_binary or "binary" (not encoded)
* enc_8bit or "8bit" (not encoded)
* The default value is "7bit"
*/
message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit;
/** The message priority
* esp_mail_smtp_priority_high or 1
* esp_mail_smtp_priority_normal or 3
* esp_mail_smtp_priority_low or 5
* The default value is esp_mail_smtp_priority_low
*/
message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low;
/** The Delivery Status Notifications e.g.
* esp_mail_smtp_notify_never
* esp_mail_smtp_notify_success
* esp_mail_smtp_notify_failure
* esp_mail_smtp_notify_delay
* The default value is esp_mail_smtp_notify_never
*/
message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay;
/* Set the custom message header */
message.addHeader("Message-ID: <abcde.fghij@gmail.com>");
/* Connect to server with the session config */
if (!smtp.connect(&session))
return;
/* Start sending Email and close the session */
if (!MailClient.sendMail(&smtp, &message))
Serial.println("Error sending Email, " + smtp.errorReason());
}
void loop()
{
}
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Print the sending result */
if (status.success())
{
Serial.println("----------------");
Serial.printf("Message sent success: %d\n", status.completedCount());
Serial.printf("Message sent failled: %d\n", status.failedCount());
Serial.println("----------------\n");
struct tm dt;
for (size_t i = 0; i < smtp.sendingResult.size(); i++)
{
/* Get the result item */
SMTP_Result result = smtp.sendingResult.getItem(i);
localtime_r(&result.timesstamp, &dt);
Serial.printf("Message No: %d\n", i + 1);
Serial.printf("Status: %s\n", result.completed ? "success" : "failed");
Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec);
Serial.printf("Recipient: %s\n", result.recipients);
Serial.printf("Subject: %s\n", result.subject);
}
Serial.println("----------------\n");
}
}

View File

@ -0,0 +1,189 @@
/**
* This example will send the Email in
* the html version.
*
*
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com
* For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
* and use the app password as password with your yahoo mail account to login.
* The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en
*/
#define SMTP_HOST "################"
/** The smtp port e.g.
* 25 or esp_mail_smtp_port_25
* 465 or esp_mail_smtp_port_465
* 587 or esp_mail_smtp_port_587
*/
#define SMTP_PORT 25
/* The log in credentials */
#define AUTHOR_EMAIL "################"
#define AUTHOR_PASSWORD "################"
/* The SMTP Session object used for Email sending */
SMTPSession smtp;
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
smtp.debug(1);
/* Set the callback function to get the sending results */
smtp.callback(smtpCallback);
/* Declare the session config data */
ESP_Mail_Session session;
/* Set the session config */
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
session.login.user_domain = "mydomain.net";
/* Declare the message class */
SMTP_Message message;
/* Set the message headers */
message.sender.name = "ESP Mail";
message.sender.email = AUTHOR_EMAIL;
message.subject = "Test sending html Email";
message.addRecipient("Admin", "####@#####_dot_com");
message.html.content = "<p>This is the <span style=\"color:#ff0000;\">html text</span> message.</p><p>The message was sent via ESP device.</p>";
/** The html text message character set e.g.
* us-ascii
* utf-8
* utf-7
* The default value is utf-8
*/
message.html.charSet = "us-ascii";
/** The content transfer encoding e.g.
* enc_7bit or "7bit" (not encoded)
* enc_qp or "quoted-printable" (encoded)
* enc_base64 or "base64" (encoded)
* enc_binary or "binary" (not encoded)
* enc_8bit or "8bit" (not encoded)
* The default value is "7bit"
*/
message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit;
/** The message priority
* esp_mail_smtp_priority_high or 1
* esp_mail_smtp_priority_normal or 3
* esp_mail_smtp_priority_low or 5
* The default value is esp_mail_smtp_priority_low
*/
message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low;
/** The Delivery Status Notifications e.g.
* esp_mail_smtp_notify_never
* esp_mail_smtp_notify_success
* esp_mail_smtp_notify_failure
* esp_mail_smtp_notify_delay
* The default value is esp_mail_smtp_notify_never
*/
message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay;
/* Set the custom message header */
message.addHeader("Message-ID: <abcde.fghij@gmail.com>");
/* Connect to server with the session config */
if (!smtp.connect(&session))
return;
/* Start sending Email and close the session */
if (!MailClient.sendMail(&smtp, &message))
Serial.println("Error sending Email, " + smtp.errorReason());
}
void loop()
{
}
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Print the sending result */
if (status.success())
{
Serial.println("----------------");
Serial.printf("Message sent success: %d\n", status.completedCount());
Serial.printf("Message sent failled: %d\n", status.failedCount());
Serial.println("----------------\n");
struct tm dt;
for (size_t i = 0; i < smtp.sendingResult.size(); i++)
{
/* Get the result item */
SMTP_Result result = smtp.sendingResult.getItem(i);
localtime_r(&result.timesstamp, &dt);
Serial.printf("Message No: %d\n", i + 1);
Serial.printf("Status: %s\n", result.completed ? "success" : "failed");
Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec);
Serial.printf("Recipient: %s\n", result.recipients);
Serial.printf("Subject: %s\n", result.subject);
}
Serial.println("----------------\n");
}
}

View File

@ -0,0 +1,227 @@
/**
* This example will send the Email with media as parallen attachments
* e.g. audio and images and play or display them simultaneously on the Email client.
*
* This depends on the Mail client supports.
*
* The html and text version messages will be sent.
*
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
/* This is for attachment data */
#include "data.h"
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com
* For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
* and use the app password as password with your yahoo mail account to login
*/
#define SMTP_HOST "################"
/** The smtp port e.g.
* 25 or esp_mail_smtp_port_25
* 465 or esp_mail_smtp_port_465
* 587 or esp_mail_smtp_port_587
*/
#define SMTP_PORT esp_mail_smtp_port_587
/* The log in credentials */
#define AUTHOR_EMAIL "################"
#define AUTHOR_PASSWORD "################"
/* The SMTP Session object used for Email sending */
SMTPSession smtp;
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
smtp.debug(1);
/* Set the callback function to get the sending results */
smtp.callback(smtpCallback);
/* Declare the session config data */
ESP_Mail_Session session;
/* Set the session config */
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
session.login.user_domain = "mydomain.net";
/* Declare the message class */
SMTP_Message message;
/* Enable the chunked data transfer with pipelining for large message if server supported */
message.enable.chunking = true;
/* Set the message headers */
message.sender.name = "ESP Mail";
message.sender.email = AUTHOR_EMAIL;
message.subject = "Test sending Email with parallel attachments";
message.addRecipient("user1", "####@#####_dot_com");
message.html.content = "<span style=\"color:#ff0000;\">This message contains image and audio file which will play on the Mail client in parallel or simultaneously (depends on the client supports).";
/** The HTML text message character set e.g.
* us-ascii
* utf-8
* utf-7
* The default value is utf-8
*/
message.html.charSet = "utf-8";
/** The content transfer encoding e.g.
* enc_7bit or "7bit" (not encoded)
* enc_qp or "quoted-printable" (encoded)
* enc_base64 or "base64" (encoded)
* enc_binary or "binary" (not encoded)
* enc_8bit or "8bit" (not encoded)
* The default value is "7bit"
*/
message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp;
message.text.content = "This message contains image and audio file which will play on the Mail client in parallel or simultaneously (depends on the client supports).";
message.text.charSet = "us-ascii";
message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64;
/** The message priority
* esp_mail_smtp_priority_high or 1
* esp_mail_smtp_priority_normal or 3
* esp_mail_smtp_priority_low or 5
* The default value is esp_mail_smtp_priority_low
*/
message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal;
/** The Delivery Status Notifications e.g.
* esp_mail_smtp_notify_never
* esp_mail_smtp_notify_success
* esp_mail_smtp_notify_failure
* esp_mail_smtp_notify_delay
* The default value is esp_mail_smtp_notify_never
*/
message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay;
/* Set the custom message header */
message.addHeader("Message-ID: <user1@gmail.com>");
/* The attachment data item */
SMTP_Attachment att;
/** Set the attachment info e.g.
* file name, MIME type, file path, file storage type,
* transfer encoding and content encoding
*/
att.descr.filename = "haun.png";
att.descr.mime = "image/png";
att.blob.data = shaun_png;
att.blob.size = sizeof(shaun_png);
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;
message.addParallelAttachment(att);
/** Set the attachment info e.g.
* file name, MIME type, file path, file storage type,
* transfer encoding and content encoding
*/
message.resetAttachItem(att); //Clear the attach item data to reuse
att.descr.filename = "mu_law.wav";
att.descr.mime = "audio/basic";
att.blob.data = mu_law_wave;
att.blob.size = sizeof(mu_law_wave);
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;
message.addParallelAttachment(att);
/* Connect to server with the session config */
if (!smtp.connect(&session))
return;
/* Start sending the Email and close the session */
if (!MailClient.sendMail(&smtp, &message, true))
Serial.println("Error sending Email, " + smtp.errorReason());
}
void loop()
{
}
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Print the sending result */
if (status.success())
{
Serial.println("----------------");
Serial.printf("Message sent success: %d\n", status.completedCount());
Serial.printf("Message sent failled: %d\n", status.failedCount());
Serial.println("----------------\n");
struct tm dt;
for (size_t i = 0; i < smtp.sendingResult.size(); i++)
{
/* Get the result item */
SMTP_Result result = smtp.sendingResult.getItem(i);
localtime_r(&result.timesstamp, &dt);
Serial.printf("Message No: %d\n", i + 1);
Serial.printf("Status: %s\n", result.completed ? "success" : "failed");
Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec);
Serial.printf("Recipient: %s\n", result.recipients);
Serial.printf("Subject: %s\n", result.subject);
}
Serial.println("----------------\n");
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,252 @@
/**
* This example will send the Email in plain text version
* with rfc822 message attachment which the rfc822 message
* also contains its attachement.
*
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
/* This is for attachment data */
#include "image.h"
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com
* For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
* and use the app password as password with your yahoo mail account to login.
* The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en
*/
#define SMTP_HOST "################"
/** The smtp port e.g.
* 25 or esp_mail_smtp_port_25
* 465 or esp_mail_smtp_port_465
* 587 or esp_mail_smtp_port_587
*/
#define SMTP_PORT 25
/* The log in credentials */
#define AUTHOR_EMAIL "################"
#define AUTHOR_PASSWORD "################"
/* The SMTP Session object used for Email sending */
SMTPSession smtp;
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
Serial.println("Connect to NTP server and set the device time\r\nPlease wait...\r\n");
float timeZone = 3;//GMT+3
float daylightOffset = 0;
/* Set the device time */
MailClient.Time.setClock(timeZone, daylightOffset);
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
smtp.debug(1);
/* Set the callback function to get the sending results */
smtp.callback(smtpCallback);
/* Declare the session config data */
ESP_Mail_Session session;
/* Set the session config */
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
session.login.user_domain = "mydomain.net";
/* Declare the message class */
SMTP_Message message;
/* Set the message headers */
message.sender.name = "ESP Mail";
message.sender.email = AUTHOR_EMAIL;
message.subject = "Test sending Email with rfc822 attachment";
message.addRecipient("Someone", "####@#####_dot_com");
message.text.content = "This is simple plain text message with rfc822 attachment";
/** The Plain text message character set e.g.
* us-ascii
* utf-8
* utf-7
* The default value is utf-8
*/
message.text.charSet = "us-ascii";
/** The content transfer encoding e.g.
* enc_7bit or "7bit" (not encoded)
* enc_qp or "quoted-printable" (encoded)
* enc_base64 or "base64" (encoded)
* enc_binary or "binary" (not encoded)
* enc_8bit or "8bit" (not encoded)
* The default value is "7bit"
*/
message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit;
/** The message priority
* esp_mail_smtp_priority_high or 1
* esp_mail_smtp_priority_normal or 3
* esp_mail_smtp_priority_low or 5
* The default value is esp_mail_smtp_priority_low
*/
message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low;
/* Set the custom message header */
message.addHeader("Message-ID: <abcde.fghij@gmail.com>");
SMTP_Message rfc822;
rfc822.messageID = "1234@local.machine.example";
rfc822.from.name = "rob";
rfc822.from.email = "rob@example.com";
rfc822.sender.name = "steve";
rfc822.sender.email = "steve@example.com";
String dt = MailClient.Time.getDateTimeString();
rfc822.date = dt.c_str();
rfc822.subject = "Test rfc822 message";
rfc822.comment = "This is comment";
rfc822.addRecipient("joe", "joe@example.com");
rfc822.response.reply_to = "rob@example.com";
rfc822.text.charSet = "utf-8";
rfc822.text.content = "This is rfc822 text message";
rfc822.text.transfer_encoding = Content_Transfer_Encoding::enc_qp;
rfc822.html.charSet = "utf-8";
rfc822.html.content = "This is rfc822 html message";
rfc822.html.transfer_encoding = Content_Transfer_Encoding::enc_base64;
/* The attachment data item */
SMTP_Attachment att;
/** Set the attachment info e.g.
* file name, MIME type, BLOB data, BLOB data size,
* and transfer encoding
*/
att.descr.filename = "firebase_logo.png";
att.descr.mime = "image/png";
att.blob.data = firebase_png;
att.blob.size = sizeof(firebase_png);
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;
/* Add the attachment to the rfc822 message */
rfc822.addAttachment(att);
/* Prepare other attachment data */
uint8_t *a = new uint8_t[512];
int j = 0;
for (int i = 0; i < 512; i++)
{
a[i] = j;
j++;
if (j > 255)
j = 0;
}
/** Set the attachment info e.g.
* file name, MIME type, BLOB data, BLOB data size.
* The default transfer encoding is base64.
*/
message.resetAttachItem(att); //Clear the attach item data to reuse
att.descr.filename = "test.dat";
att.descr.mime = "application/octet-stream";
att.blob.data = a;
att.blob.size = 512;
/* Add this attachment to the message */
message.addAttachment(att);
/* Add rfc822 message in the message */
message.addRMessage(rfc822);
/* Connect to server with the session config */
if (!smtp.connect(&session))
return;
/* Start sending Email and close the session */
if (!MailClient.sendMail(&smtp, &message))
Serial.println("Error sending Email, " + smtp.errorReason());
}
void loop()
{
}
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Print the sending result */
if (status.success())
{
Serial.println("----------------");
Serial.printf("Message sent success: %d\n", status.completedCount());
Serial.printf("Message sent failled: %d\n", status.failedCount());
Serial.println("----------------\n");
struct tm dt;
for (size_t i = 0; i < smtp.sendingResult.size(); i++)
{
/* Get the result item */
SMTP_Result result = smtp.sendingResult.getItem(i);
localtime_r(&result.timesstamp, &dt);
Serial.printf("Message No: %d\n", i + 1);
Serial.printf("Status: %s\n", result.completed ? "success" : "failed");
Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec);
Serial.printf("Recipient: %s\n", result.recipients);
Serial.printf("Subject: %s\n", result.subject);
}
Serial.println("----------------\n");
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,245 @@
/**
* This example will send multiple messages which
* the session was keep open during sending.
*
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com
* For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
* and use the app password as password with your yahoo mail account to login.
* The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en
*/
#define SMTP_HOST "################"
/** The smtp port e.g.
* 25 or esp_mail_smtp_port_25
* 465 or esp_mail_smtp_port_465
* 587 or esp_mail_smtp_port_587
*/
#define SMTP_PORT esp_mail_smtp_port_587
/* The log in credentials */
#define AUTHOR_EMAIL "################"
#define AUTHOR_PASSWORD "################"
/* The SMTP Session object used for Email sending */
SMTPSession smtp;
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
smtp.debug(1);
/* Set the callback function to get the sending results */
smtp.callback(smtpCallback);
/* Declare the session config data */
ESP_Mail_Session session;
/* Set the session config */
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
session.login.user_domain = "mydomain.net";
/* Declare the message class */
SMTP_Message message;
/* Set the message headers */
message.sender.name = "ESP Mail";
message.sender.email = AUTHOR_EMAIL;
message.subject = "First Email with session reusage";
message.addRecipient("Admin1", "####@#####_dot_com");
message.addRecipient("Admin2", "####@#####_dot_com");
message.addCc("####@#####_dot_com");
message.addBcc("####@#####_dot_com");
message.html.content = "<p>This is the <span style=\"color:#ff0000;\">first message</span>.</p>";
/** The HTML text message character set e.g.
* us-ascii
* utf-8
* utf-7
* The default value is utf-8
*/
message.html.charSet = "utf-8";
/** The content transfer encoding e.g.
* enc_7bit or "7bit" (not encoded)
* enc_qp or "quoted-printable" (encoded)
* enc_base64 or "base64" (encoded)
* enc_binary or "binary" (not encoded)
* enc_8bit or "8bit" (not encoded)
* The default value is "7bit"
*/
message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp;
/** The option to add soft line break to to the message for
* the long text message > 78 characters (rfc 3676)
* Some Servers may not compliant with the standard.
*/
message.text.flowed = true;
message.text.content = "This is the first message";
message.text.charSet = "us-ascii";
message.html.transfer_encoding = Content_Transfer_Encoding::enc_base64;
/** The message priority
* esp_mail_smtp_priority_high or 1
* esp_mail_smtp_priority_normal or 3
* esp_mail_smtp_priority_low or 5
* The default value is esp_mail_smtp_priority_low
*/
message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal;
/** The Delivery Status Notifications e.g.
* esp_mail_smtp_notify_never
* esp_mail_smtp_notify_success
* esp_mail_smtp_notify_failure
* esp_mail_smtp_notify_delay
* The default value is esp_mail_smtp_notify_never
*/
message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay;
/* Set the custom message header */
message.addHeader("Message-ID: <Admin1@gmail.com>");
Serial.println();
Serial.println("Sending first Email...");
/* Connect to server with the session config */
if (!smtp.connect(&session))
return;
/** Start sending the first Email and keep open the session
* The third parameter is for close the session.
*/
if (!MailClient.sendMail(&smtp, &message, false))
Serial.println("Error sending Email, " + smtp.errorReason());
/* To clear all message data */
//message.clear();
/** Clear primary recipients, Cc recipients, Bcc recipients, custom headers
* attachments and inline images
*/
message.clearRecipients();
message.clearCc();
message.clearBcc();
//message.clearAttachments();
//message.clearInlineimages();
message.subject = "Second Email with session reusage";
message.addRecipient("Admin3", "####@#####_dot_com");
message.addRecipient("Admin4", "####@#####_dot_com");
message.addCc("####@#####_dot_com");
message.addBcc("####@#####_dot_com");
message.html.content = "<p>This is the <span style=\"color:#ff0000;\">second message</span>.</p>";
message.html.charSet = "us-ascii";
message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit;
message.text.content = "This is the second message";
message.text.charSet = "UTF-8";
message.text.transfer_encoding = Content_Transfer_Encoding::enc_qp;
/* Set the custom message header */
message.addHeader("Message-ID: <Admin3@gmail.com>");
Serial.println();
Serial.println("Sending second Email...");
/* Start sending the second mail and close the session */
if (!MailClient.sendMail(&smtp, &message))
Serial.println("Error sending Email, " + smtp.errorReason());
}
void loop()
{
}
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Print the sending result */
if (status.success())
{
Serial.println("----------------");
Serial.printf("Message sent success: %d\n", status.completedCount());
Serial.printf("Message sent failled: %d\n", status.failedCount());
Serial.println("----------------\n");
struct tm dt;
for (size_t i = 0; i < smtp.sendingResult.size(); i++)
{
/* Get the result item */
SMTP_Result result = smtp.sendingResult.getItem(i);
localtime_r(&result.timesstamp, &dt);
Serial.printf("Message No: %d\n", i + 1);
Serial.printf("Status: %s\n", result.completed ? "success" : "failed");
Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec);
Serial.printf("Recipient: %s\n", result.recipients);
Serial.printf("Subject: %s\n", result.subject);
}
Serial.println("----------------\n");
}
}

View File

@ -0,0 +1,185 @@
/**
* This example will send the Email in plain text version.
*
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com
* For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
* and use the app password as password with your yahoo mail account to login.
* The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en
*/
#define SMTP_HOST "################"
/** The smtp port e.g.
* 25 or esp_mail_smtp_port_25
* 465 or esp_mail_smtp_port_465
* 587 or esp_mail_smtp_port_587
*/
#define SMTP_PORT 25
/* The sign in credentials */
#define AUTHOR_EMAIL "################"
#define AUTHOR_PASSWORD "################"
/* The SMTP Session object used for Email sending */
SMTPSession smtp;
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
smtp.debug(1);
/* Set the callback function to get the sending results */
smtp.callback(smtpCallback);
/* Declare the session config data */
ESP_Mail_Session session;
/* Set the session config */
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
session.login.user_domain = "mydomain.net";
/* Declare the message class */
SMTP_Message message;
/* Set the message headers */
message.sender.name = "ESP Mail";
message.sender.email = AUTHOR_EMAIL;
message.subject = "Test sending plain text Email";
message.addRecipient("Someone", "####@#####_dot_com");
message.text.content = "This is simple plain text message";
/** The Plain text message character set e.g.
* us-ascii
* utf-8
* utf-7
* The default value is utf-8
*/
message.text.charSet = "us-ascii";
/** The content transfer encoding e.g.
* enc_7bit or "7bit" (not encoded)
* enc_qp or "quoted-printable" (encoded)
* enc_base64 or "base64" (encoded)
* enc_binary or "binary" (not encoded)
* enc_8bit or "8bit" (not encoded)
* The default value is "7bit"
*/
message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit;
/** The message priority
* esp_mail_smtp_priority_high or 1
* esp_mail_smtp_priority_normal or 3
* esp_mail_smtp_priority_low or 5
* The default value is esp_mail_smtp_priority_low
*/
message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low;
/** The Delivery Status Notifications e.g.
* esp_mail_smtp_notify_never
* esp_mail_smtp_notify_success
* esp_mail_smtp_notify_failure
* esp_mail_smtp_notify_delay
* The default value is esp_mail_smtp_notify_never
*/
message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay;
/* Set the custom message header */
message.addHeader("Message-ID: <abcde.fghij@gmail.com>");
/* Connect to server with the session config */
if (!smtp.connect(&session))
return;
/* Start sending Email and close the session */
if (!MailClient.sendMail(&smtp, &message))
Serial.println("Error sending Email, " + smtp.errorReason());
}
void loop()
{
}
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Print the sending result */
if (status.success())
{
Serial.println("----------------");
Serial.printf("Message sent success: %d\n", status.completedCount());
Serial.printf("Message sent failled: %d\n", status.failedCount());
Serial.println("----------------\n");
struct tm dt;
for (size_t i = 0; i < smtp.sendingResult.size(); i++)
{
/* Get the result item */
SMTP_Result result = smtp.sendingResult.getItem(i);
localtime_r(&result.timesstamp, &dt);
Serial.printf("Message No: %d\n", i + 1);
Serial.printf("Status: %s\n", result.completed ? "success" : "failed");
Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec);
Serial.printf("Recipient: %s\n", result.recipients);
Serial.printf("Subject: %s\n", result.subject);
}
Serial.println("----------------\n");
}
}

View File

@ -0,0 +1,197 @@
/**
* This example will send the Email in plain text version
* with the quoted text and long line text.
*
*
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com
* For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
* and use the app password as password with your yahoo mail account to login.
* The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en
*/
#define SMTP_HOST "################"
/** The smtp port e.g.
* 25 or esp_mail_smtp_port_25
* 465 or esp_mail_smtp_port_465
* 587 or esp_mail_smtp_port_587
*/
#define SMTP_PORT 25
/* The log in credentials */
#define AUTHOR_EMAIL "################"
#define AUTHOR_PASSWORD "################"
/* The SMTP Session object used for Email sending */
SMTPSession smtp;
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
smtp.debug(1);
/* Set the callback function to get the sending results */
smtp.callback(smtpCallback);
/* Declare the session config data */
ESP_Mail_Session session;
/* Set the session config */
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
session.login.user_domain = "mydomain.net";
/* Declare the message class */
SMTP_Message message;
/* Set the message headers */
message.sender.name = "ESP Mail";
message.sender.email = AUTHOR_EMAIL;
message.subject = "Test sending flowed plain text Email";
message.addRecipient("Someone", "####@#####_dot_com");
/** The option to add soft line break to to the message for
* the long text message > 78 characters (rfc 3676)
* Some Servers may not compliant with the standard.
*/
message.text.flowed = true;
/** if the option message.text.flowed is true,
* the following plain text message will be wrapped.
*/
message.text.content = "The text below is the long quoted text which breaks into several lines.\r\n\r\n>> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\r\n\r\nThis is the normal short text.\r\n\r\nAnother long text, abcdefg hijklmnop qrstuv wxyz abcdefg hijklmnop qrstuv wxyz abcdefg hijklmnop qrstuv wxyz.";
/** The Plain text message character set e.g.
* us-ascii
* utf-8
* utf-7
* The default value is utf-8
*/
message.text.charSet = "us-ascii";
/** The content transfer encoding e.g.
* enc_7bit or "7bit" (not encoded)
* enc_qp or "quoted-printable" (encoded)
* enc_base64 or "base64" (encoded)
* enc_binary or "binary" (not encoded)
* enc_8bit or "8bit" (not encoded)
* The default value is "7bit"
*/
message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit;
/** The message priority
* esp_mail_smtp_priority_high or 1
* esp_mail_smtp_priority_normal or 3
* esp_mail_smtp_priority_low or 5
* The default value is esp_mail_smtp_priority_low
*/
message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low;
/** The Delivery Status Notifications e.g.
* esp_mail_smtp_notify_never
* esp_mail_smtp_notify_success
* esp_mail_smtp_notify_failure
* esp_mail_smtp_notify_delay
* The default value is esp_mail_smtp_notify_never
*/
message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay;
/* Set the custom message header */
message.addHeader("Message-ID: <abcde.fghij@gmail.com>");
/* Connect to server with the session config */
if (!smtp.connect(&session))
return;
/* Start sending Email and close the session */
if (!MailClient.sendMail(&smtp, &message))
Serial.println("Error sending Email, " + smtp.errorReason());
}
void loop()
{
}
/* Callback function to get the Email sending status */
void smtpCallback(SMTP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Print the sending result */
if (status.success())
{
Serial.println("----------------");
Serial.printf("Message sent success: %d\n", status.completedCount());
Serial.printf("Message sent failled: %d\n", status.failedCount());
Serial.println("----------------\n");
struct tm dt;
for (size_t i = 0; i < smtp.sendingResult.size(); i++)
{
/* Get the result item */
SMTP_Result result = smtp.sendingResult.getItem(i);
localtime_r(&result.timesstamp, &dt);
Serial.printf("Message No: %d\n", i + 1);
Serial.printf("Status: %s\n", result.completed ? "success" : "failed");
Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec);
Serial.printf("Recipient: %s\n", result.recipients);
Serial.printf("Subject: %s\n", result.subject);
}
Serial.println("----------------\n");
}
}

View File

@ -0,0 +1,363 @@
/**
* This example will set the argument to the flags and read the message.
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
*
*/
/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "################"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "################"
#define AUTHOR_PASSWORD "################"
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status);
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(IMAPSession &imap);
/* Print all messages from the message list */
void printMessages(IMAPSession &imap);
/* Print all rfc822 messages included in the message */
void printRFC822Messages(IMAP_MSG_Item &msg);
/* Print all attachments info from the message */
void printAttacements(IMAP_MSG_Item &msg);
/* The IMAP Session object used for Email reading */
IMAPSession imap;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
/** Enable the debug via Serial port
* none debug or 0
* basic debug or 1
*/
imap.debug(1);
/* Set the callback function to get the reading results */
imap.callback(imapCallback);
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Declare the session config data */
ESP_Mail_Session session;
/* Set the session config */
session.server.host_name = IMAP_HOST;
session.server.port = IMAP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
/* Setup the configuration for searching or fetching operation and its result */
IMAP_Config config;
/* Message UID to fetch or read e.g. 100 */
config.fetch.uid = "100";
/* Set seen flag */
//config.fetch.set_seen = true;
/* Search criteria */
config.search.criteria = "";
/* Also search the unseen message */
config.search.unseen_msg = true;
/* Set the storage to save the downloaded files and attachments */
config.storage.saved_path = "/email_data";
/** The file storage type e.g.
* esp_mail_file_storage_type_none,
* esp_mail_file_storage_type_flash, and
* esp_mail_file_storage_type_sd
*/
config.storage.type = esp_mail_file_storage_type_flash;
/** Set to download heades, text and html messaeges,
* attachments and inline images respectively.
*/
config.download.header = true;
config.download.text = true;
config.download.html = true;
config.download.attachment = true;
config.download.inlineImg = true;
/** Set to enable the results i.e. html and text messaeges
* which the content stored in the IMAPSession object is limited
* by the option config.limit.msg_size.
* The whole message can be download through config.download.text
* or config.download.html which not depends on these enable options.
*/
config.enable.html = true;
config.enable.text = true;
/* Set to enable the sort the result by message UID in the ascending order */
config.enable.recent_sort = true;
/* Set to report the download progress via the default serial port */
config.enable.download_status = true;
/* Set the limit of number of messages in the search results */
config.limit.search = 5;
/** Set the maximum size of message stored in
* IMAPSession object in byte
*/
config.limit.msg_size = 512;
/** Set the maximum attachments and inline images files size
* that can be downloaded in byte.
* The file which its size is largger than this limit may be saved
* as truncated file.
*/
config.limit.attachment_size = 1024 * 1024 * 5;
/* Connect to server with the session and config */
if (!imap.connect(&session, &config))
return;
/* {Optional] */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder("INBOX"))
return;
/* {Optional] */
printSelectedMailboxInfo(imap);
/** Set \Seen and \Answered to flags for message with UID 100
* The seesion will keep open.
*/
if (MailClient.setFlag(&imap, 100, "\\Seen \\Answered", false))
Serial.println("Setting FLAG success");
else
Serial.println("Error, setting FLAG");
/* Add \Seen and \Answered to flags for message with UID 100 */
//MailClient.addFlag(imap, 100, "\\Seen \\Answered", false);
/* Remove \Seen and \Answered from flags for message with UID 100 */
//MailClient.removeFlag(imap, 100, "\\Seen \\Answered", false);
/* Read or search the Email and close the session */
MailClient.readMail(&imap);
/* Clear all stored data in IMAPSession object */
imap.empty();
}
void loop()
{
}
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Show the result when reading finished */
if (status.success())
{
/* Print the result */
printMessages(imap);
/* Clear all stored data in IMAPSession object */
imap.empty();
Serial.printf("Free Heap: %d", ESP.getFreeHeap());
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
Serial.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(IMAPSession &imap)
{
/* Declare the selected folder info class to get the info of selected mailbox folder */
SelectedFolderInfo sFolder = imap.selectedFolder();
/* Show the mailbox info */
Serial.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
Serial.printf("Predicted next UID: %d\n", sFolder.nextUID());
for (size_t i = 0; i < sFolder.flagCount(); i++)
Serial.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
}
void printRFC822Messages(IMAP_MSG_Item &msg)
{
Serial.printf("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size());
for (size_t j = 0; j < msg.rfc822.size(); j++)
{
IMAP_MSG_Item rfc822 = msg.rfc822[j];
Serial.printf("%d. \n", j + 1);
Serial.printf("Messsage ID: %s\n", rfc822.messageID);
Serial.printf("From: %s\n", rfc822.from);
Serial.printf("Sender: %s\n", rfc822.sender);
Serial.printf("To: %s\n", rfc822.to);
Serial.printf("CC: %s\n", rfc822.cc);
Serial.printf("Subject: %s\n", rfc822.subject);
Serial.printf("Date: %s\n", rfc822.date);
Serial.printf("Reply-To: %s\n", rfc822.reply_to);
Serial.printf("Return-Path: %s\n", rfc822.return_path);
Serial.printf("Comment: %s\n", rfc822.comment);
Serial.printf("Keyword: %s\n", rfc822.keyword);
Serial.printf("Text Message: %s\n", rfc822.text.content);
Serial.printf("Text Message Charset: %s\n", rfc822.text.charSet);
Serial.printf("Text Message Transfer Encoding: %s\n", rfc822.text.transfer_encoding);
Serial.printf("HTML Message: %s\n", rfc822.html.content);
Serial.printf("HTML Message Charset: %s\n", rfc822.html.charSet);
Serial.printf("HTML Message Transfer Encoding: %s\n\n", rfc822.html.transfer_encoding);
if (rfc822.attachments.size() > 0)
printAttacements(rfc822);
}
}
void printAttacements(IMAP_MSG_Item &msg)
{
Serial.printf("Attachment: %d file(s)\n****************************\n", msg.attachments.size());
for (size_t j = 0; j < msg.attachments.size(); j++)
{
IMAP_Attach_Item att = msg.attachments[j];
/** att.type can be
* esp_mail_att_type_none or 0
* esp_mail_att_type_attachment or 1
* esp_mail_att_type_inline or 2
*/
Serial.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.creationDate);
}
Serial.println();
}
void printMessages(IMAPSession &imap)
{
/* Get the message list from the message list data */
IMAP_MSG_List msgList = imap.data();
for (size_t i = 0; i < msgList.msgItems.size(); i++)
{
/* Iterate to get each message data through the message item data */
IMAP_MSG_Item msg = msgList.msgItems[i];
Serial.println("################################");
Serial.printf("Messsage Number: %s\n", msg.msgNo);
Serial.printf("Messsage UID: %s\n", msg.UID);
Serial.printf("Messsage ID: %s\n", msg.ID);
Serial.printf("Accept Language: %s\n", msg.acceptLang);
Serial.printf("Content Language: %s\n", msg.contentLang);
Serial.printf("From: %s\n", msg.from);
Serial.printf("From Charset: %s\n", msg.fromCharset);
Serial.printf("To: %s\n", msg.to);
Serial.printf("To Charset: %s\n", msg.toCharset);
Serial.printf("CC: %s\n", msg.cc);
Serial.printf("CC Charset: %s\n", msg.ccCharset);
Serial.printf("Date: %s\n", msg.date);
Serial.printf("Subject: %s\n", msg.subject);
Serial.printf("Subject Charset: %s\n", msg.subjectCharset);
/* If the result contains the message info (Fetch mode) */
if (!imap.headerOnly())
{
Serial.printf("Text Message: %s\n", msg.text.content);
Serial.printf("Text Message Charset: %s\n", msg.text.charSet);
Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
Serial.printf("HTML Message: %s\n", msg.html.content);
Serial.printf("HTML Message Charset: %s\n", msg.html.charSet);
Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
if (msg.attachments.size() > 0)
printAttacements(msg);
if (msg.rfc822.size() > 0)
printRFC822Messages(msg);
}
Serial.println();
}
}

126
lib/lib_div/lib_mail/keywords.txt Executable file
View File

@ -0,0 +1,126 @@
######################################
# Syntax Coloring Map ESP Mail Client
######################################
#######################################
# Classes and Structured Type (KEYWORD1)
#######################################
MailClient KEYWORD1
IMAPSession KEYWORD1
SMTPSession KEYWORD1
SMTP_Message KEYWORD1
IMAP_Config KEYWORD1
FoldersCollection KEYWORD1
imapStatusCallback KEYWORD1
IMAP_MSG_List KEYWORD1
SelectedFolderInfo KEYWORD1
ESP_Mail_Session KEYWORD1
smtpStatusCallback KEYWORD1
SMTP_Attachment KEYWORD1
SMTP_Result KEYWORD1
IMAP_MSG_Item KEYWORD1
Content_Transfer_Encoding KEYWORD1
MessageList KEYWORD1
###############################################
# Methods and Functions (KEYWORD2)
###############################################
sendMail KEYWORD2
readMail KEYWORD2
setFlag KEYWORD2
addFlag KEYWORD2
removeFlag KEYWORD2
sdBegin KEYWORD2
connect KEYWORD2
closeSession KEYWORD2
debug KEYWORD2
getFolders KEYWORD2
selectFolder KEYWORD2
openFolder KEYWORD2
closeFolder KEYWORD2
callback KEYWORD2
headerOnly KEYWORD2
data KEYWORD2
selectedFolder KEYWORD2
errorReason KEYWORD2
empty KEYWORD2
resetAttachItem KEYWORD2
clear KEYWORD2
clearInlineimages KEYWORD2
clearAttachments KEYWORD2
clearRFC822Messages KEYWORD2
clearRecipients KEYWORD2
clearCc KEYWORD2
clearBcc KEYWORD2
clearHeader KEYWORD2
addAttachment KEYWORD2
addParallelAttachment KEYWORD2
addInlineImage KEYWORD2
addMessage KEYWORD2
addRecipient KEYWORD2
addCc KEYWORD2
addBcc KEYWORD2
addHeader KEYWORD2
info KEYWORD2
successs KEYWORD2
completedCount KEYWORD2
failedCount KEYWORD2
getItem KEYWORD2
size KEYWORD2
flagCount KEYWORD2
msgCount KEYWORD2
nextUID KEYWORD2
searchCount KEYWORD2
availableMessages KEYWORD2
flag KEYWORD2
setClock KEYWORD2
getUnixTime KEYWORD2
getTimestamp KEYWORD2
getYear KEYWORD2
getMonth KEYWORD2
getDay KEYWORD2
getDayOfWeek KEYWORD2
getDayOfWeekString KEYWORD2
getHour KEYWORD2
getMin KEYWORD2
getSecond KEYWORD2
getNumberOfDayThisYear KEYWORD2
getTotalDays KEYWORD2
dayofWeek KEYWORD2
getCurrentSecond KEYWORD2
getCurrentTimestamp KEYWORD2
getTimeFromSec KEYWORD2
getDateTimeString KEYWORD2
copyMessages KEYWORD2
deleteMessages KEYWORD2
createFolder KEYWORD2
deleteFolder KEYWORD2
#######################################
# Struct (LITERAL1)
#######################################
esp_mail_email_info_t LITERAL1
esp_mail_plain_body_t LITERAL1
esp_mail_html_body_t LITERAL1
esp_mail_smtp_msg_response_t LITERAL1
esp_mail_smtp_enable_option_t LITERAL1
esp_mail_email_info_t LITERAL1
esp_mail_folder_info_item_t LITERAL1
esp_mail_sesson_sever_config_t LITERAL1
esp_mail_sesson_login_config_t LITERAL1
esp_mail_sesson_secure_config_t LITERAL1
esp_mail_sesson_cert_config_t LITERAL1
esp_mail_imap_fetch_config_t LITERAL1
esp_mail_imap_search_config_t LITERAL1
esp_mail_imap_limit_config_t LITERAL1
esp_mail_imap_enable_config_t LITERAL1
esp_mail_imap_download_config_t LITERAL1
esp_mail_imap_storage_config_t LITERAL1
esp_mail_file_storage_type_none LITERAL1
esp_mail_file_storage_type_flash LITERAL1
esp_mail_file_storage_type_sd LITERAL1

View File

@ -0,0 +1,16 @@
{
"name": "ESP Mail Client",
"version": "1.0.13",
"keywords": "communication, email, imap, smtp, esp32, esp8266, arduino",
"description": "Mail Client Arduino Library for Espressif ESP32 and ESP8266 devices. This library allows the ESP32 and ESP8266 devices to send and read Email with the many options and features e.g. the attachments, inline images, embeded rfc822 messages are supported for upload when sending and download when reading the Emails.",
"repository": {
"type": "git",
"url": "https://github.com/mobizt/ESP-Mail-Client.git"
},
"authors": [{
"name": "Mobizt",
"email": "suwatchai@outlook.com"
}],
"frameworks": "arduino",
"platforms": "espressif32, espressif8266"
}

View File

@ -0,0 +1,9 @@
name=ESP Mail Client
version=1.0.13
author=Mobizt
maintainer=Mobizt <suwatchai@outlook.com>
sentence=Mail Client Arduino Library for Espressif ESP32 and ESP8266 devices.
paragraph=This library allows the ESP32 and ESP8266 devices to send and read Email with the many options and features e.g. the attachments, inline images, embeded rfc822 messages are supported for upload when sending and download when reading the Emails.
category=Communication
url=https://github.com/mobizt/ESP-Mail-Client
architectures=esp32,esp8266

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1949
lib/lib_div/lib_mail/src/README.md Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,279 @@
/*
* ESP32 Internet Time Helper Arduino Library v 1.0.1
*
* The MIT License (MIT)
* Copyright (c) 2019 K. Suwatchai (Mobizt)
*
*
* Permission is hereby granted, free of charge, to any person returning 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.
*/
#ifndef ESPTimeHelper_CPP
#define ESPTimeHelper_CPP
#include "ESPTimeHelper.h"
ESPTimeHelper::ESPTimeHelper()
{
}
uint32_t ESPTimeHelper::getUnixTime()
{
uint32_t utime = (msec_time_diff + millis()) / 1000;
return utime;
}
time_t ESPTimeHelper::getTimestamp(int year, int mon, int date, int hour, int mins, int sec)
{
struct tm timeinfo;
timeinfo.tm_year = year - 1900;
timeinfo.tm_mon = mon - 1;
timeinfo.tm_mday = date;
timeinfo.tm_hour = hour;
timeinfo.tm_min = mins;
timeinfo.tm_sec = sec;
time_t ts = mktime(&timeinfo);
return ts;
}
bool ESPTimeHelper::setClock(float gmtOffset, float daylightOffset)
{
TZ = gmtOffset;
DST_MN = daylightOffset;
configTime((TZ)*3600, (DST_MN)*60, "pool.ntp.org", "time.nist.gov");
now = time(nullptr);
uint8_t attempts = 0;
while (now < 1577836800)
{
now = time(nullptr);
attempts++;
if (attempts > 200 || now > 1577836800)
break;
delay(100);
}
uint64_t tmp = now;
tmp = tmp * 1000;
msec_time_diff = tmp - millis();
#if defined(ESP32)
getLocalTime(&timeinfo);
#elif defined(ESP8266)
gmtime_r(&now, &timeinfo);
#endif
clockReady = now > 8 * 3600 * 2;
return clockReady;
}
int ESPTimeHelper::getYear()
{
setSysTime();
return timeinfo.tm_year + 1900;
}
int ESPTimeHelper::getMonth()
{
setSysTime();
return timeinfo.tm_mon + 1;
}
int ESPTimeHelper::getDay()
{
setSysTime();
return timeinfo.tm_mday;
}
int ESPTimeHelper::getDayOfWeek()
{
setSysTime();
return timeinfo.tm_wday;
}
String ESPTimeHelper::getDayOfWeekString()
{
setSysTime();
return dow[timeinfo.tm_wday];
}
int ESPTimeHelper::getHour()
{
setSysTime();
return timeinfo.tm_hour;
}
int ESPTimeHelper::getMin()
{
setSysTime();
return timeinfo.tm_min;
}
int ESPTimeHelper::getSec()
{
setSysTime();
return timeinfo.tm_sec;
}
int ESPTimeHelper::getNumberOfDayThisYear()
{
setSysTime();
return timeinfo.tm_yday + 1;
}
int ESPTimeHelper::totalDays(int y, int m, int d)
{
static char daytab[2][13] =
{
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
int daystotal = d;
for (int year = 1; year <= y; year++)
{
int max_month = (year < y ? 12 : m - 1);
int leap = (year % 4 == 0);
if (year % 100 == 0 && year % 400 != 0)
leap = 0;
for (int month = 1; month <= max_month; month++)
{
daystotal += daytab[leap][month];
}
}
return daystotal;
}
int ESPTimeHelper::getTotalDays(int year, int month, int day)
{
return totalDays(year, month, day) - totalDays(1970, 1, 1);
}
int ESPTimeHelper::dayofWeek(int year, int month, int day) /* 1 <= m <= 12, y > 1752 (in the U.K.) */
{
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
year -= month < 3;
return (year + year / 4 - year / 100 + year / 400 + t[month - 1] + day) % 7;
}
int ESPTimeHelper::getCurrentSecond()
{
return (timeinfo.tm_hour * 3600) + (timeinfo.tm_min * 60) + timeinfo.tm_sec;
}
uint64_t ESPTimeHelper::getCurrentTimestamp()
{
return now;
}
struct tm ESPTimeHelper::getTimeFromSec(int seconds)
{
struct tm timeinfo;
int _yrs = seconds / (365 * 24 * 3600);
seconds = seconds - _yrs * (365 * 24 * 3600);
timeinfo.tm_year = _yrs - 1900;
int _months = seconds / (30 * 24 * 3600);
seconds = seconds - _months * (30 * 24 * 3600);
timeinfo.tm_mon = _months - 1;
int _days = seconds / (24 * 3600);
seconds = seconds - _days * (24 * 3600);
timeinfo.tm_mday = _days;
int _hr = seconds / 3600;
seconds = seconds - _hr * 3600;
timeinfo.tm_hour = _hr;
int _min = seconds / 60;
seconds = seconds - _min * 60;
timeinfo.tm_min = _min;
timeinfo.tm_sec = seconds;
return timeinfo;
}
char *ESPTimeHelper::intStr(int value)
{
char *buf = new char[36];
memset(buf, 0, 36);
itoa(value, buf, 10);
return buf;
}
String ESPTimeHelper::getDateTimeString()
{
setSysTime();
std::string s;
s = sdow[timeinfo.tm_wday];
s += ", ";
char *tmp = intStr(timeinfo.tm_mday);
s += tmp;
delete[] tmp;
s += " ";
s += months[timeinfo.tm_mon];
s += " ";
tmp = intStr(timeinfo.tm_year + 1900);
s += tmp;
delete[] tmp;
s += " ";
if (timeinfo.tm_hour < 10)
s += "0";
tmp = intStr(timeinfo.tm_hour);
s += tmp;
delete[] tmp;
s += ":";
if (timeinfo.tm_min < 10)
s += "0";
tmp = intStr(timeinfo.tm_min);
s += tmp;
delete[] tmp;
s += ":";
if (timeinfo.tm_sec < 10)
s += "0";
tmp = intStr(timeinfo.tm_sec);
s += tmp;
delete[] tmp;
int p = 1;
if (TZ < 0)
p = -1;
int tz = TZ;
float dif = (p * (TZ - tz)) * 60.0;
if (TZ < 0)
s += " -";
else
s += " +";
if (tz < 10)
s += "0";
tmp = intStr(tz);
s += tmp;
delete[] tmp;
if (dif < 10)
s += "0";
tmp = intStr((int)dif);
s += tmp;
delete[] tmp;
return s.c_str();
}
void ESPTimeHelper::setSysTime()
{
#if defined(ESP32)
getLocalTime(&timeinfo);
#elif defined(ESP8266)
now = time(nullptr);
localtime_r(&now, &timeinfo);
#endif
}
#endif //ESPTimeHelper_CPP

View File

@ -0,0 +1,191 @@
/*
* ESP8266/ESP32 Internet Time Helper Arduino Library v 1.0.1
*
* The MIT License (MIT)
* Copyright (c) 2020 K. Suwatchai (Mobizt)
*
*
* Permission is hereby granted, free of charge, to any person returning 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.
*/
#ifndef ESPTimeHelper_H
#define ESPTimeHelper_H
#include <time.h>
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif
class ESPTimeHelper
{
public:
ESPTimeHelper();
/** Set the system time from the NTP server
*
* @param gmtOffset The GMT time offset in hour.
* @param daylightOffset The Daylight time offset in hour.
* @return boolean The status indicates the success of operation.
*
* @note This requires internet connection
*/
bool setClock(float gmtOffset, float daylightOffset);
/** Provide the Unix time
*
* @return uint32_t The value of current Unix time.
*/
uint32_t getUnixTime();
/** Provide the timestamp from the year, month, date, hour, minute,
* and second provided.
*
* @param year The year.
* @param mon The month from 1 to 12.
* @param date The dates.
* @param hour The hours.
* @param mins The minutes.
* @param sec The seconds.
* @return time_t The value of timestamp.
*/
time_t getTimestamp(int year, int mon, int date, int hour, int mins, int sec);
/** Provide the current year.
*
* @return int The value of current year.
*/
int getYear();
/** Provide the current month.
*
* @return int The value of current month.
*/
int getMonth();
/** Provide the current date.
*
* @return int The value of current date.
*/
int getDay();
/** Provide the current day of week.
*
* @return int The value of current day of week.
*
* @note 1 for sunday and 7 for saturday.
*/
int getDayOfWeek();
/** Provide the current day of week in String.
*
* @return String The value of day of week.
*/
String getDayOfWeekString();
/** Provide the current hour.
*
* @return int The value of current hour (0 to 23).
*/
int getHour();
/** Provide the current minute.
*
* @return int The value of current minute.
*/
int getMin();
/** Provide the current second.
*
* @return int The value of current second.
*/
int getSec();
/** Provide the total days of current year.
*
* @return int The value of total days of current year.
*/
int getNumberOfDayThisYear();
/** Provide the total days of from January 1, 1970 to specific date.
*
* @param year The year from 1970.
* @param mon The month from 1 to 12.
* @param day The dates.
* @return int The value of total days.
*/
int getTotalDays(int year, int month, int day);
/** Provide the day of week from specific date.
*
* @param year The year from 1970.
* @param mon The month from 1 to 12.
* @param day The dates.
* @return int the value of day of week.
* @note 1 for sunday and 7 for saturday
*/
int dayofWeek(int year, int month, int day);
/** Provide the second of current hour.
*
* @return int The value of current second.
*/
int getCurrentSecond();
/** Provide the current timestamp.
*
* @return uint64_t The value of current timestamp.
*/
uint64_t getCurrentTimestamp();
/** Provide the date and time from second counted from January 1, 1970.
*
* @param sec The seconds from January 1, 1970 00.00.
* @return tm The tm structured data.
*
* @note The returned structured data tm has the members e.g.
* tm_year (from 1900), tm_mon (from 0 to 11), tm_mday, tm_hour,
* tm_min and tm_sec.
*/
struct tm getTimeFromSec(int seconds);
/** Provide the current date time string that valid for Email.
*
* @return String The current date time string.
*/
String getDateTimeString();
time_t now;
uint64_t msec_time_diff = 0;
struct tm timeinfo;
float TZ = 0.0;
uint8_t DST_MN = 0;
bool clockReady = false;
private:
int totalDays(int y, int m, int d);
char *intStr(int value);
void setSysTime();
const char *dow[7] = {"sunday", "monday", "tuesday", "wednesday", "thurseday", "friday", "saturday"};
const char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
const char *sdow[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
};
#endif //ESPTimeHelper_H

View File

@ -0,0 +1,8 @@
/*
To use LittleFS file system instead of SPIFFS, uncomment the following line
*/
//#define USE_LITTLEFS

View File

@ -0,0 +1,65 @@
#ifndef MIMEInfo_H
#define MIMEInfo_H
#include <Arduino.h>
enum esp_mail_file_extension
{
esp_mail_file_extension_html,
esp_mail_file_extension_htm,
esp_mail_file_extension_css,
esp_mail_file_extension_txt,
esp_mail_file_extension_js,
esp_mail_file_extension_json,
esp_mail_file_extension_png,
esp_mail_file_extension_gif,
esp_mail_file_extension_jpg,
esp_mail_file_extension_ico,
esp_mail_file_extension_svg,
esp_mail_file_extension_ttf,
esp_mail_file_extension_otf,
esp_mail_file_extension_woff,
esp_mail_file_extension_woff2,
esp_mail_file_extension_eot,
esp_mail_file_extension_sfnt,
esp_mail_file_extension_xml,
esp_mail_file_extension_pdf,
esp_mail_file_extension_zip,
esp_mail_file_extension_gz,
esp_mail_file_extension_appcache,
esp_mail_file_extension_none,
esp_mail_file_extension_maxType
};
struct esp_mail_mime_prop_t
{
char endsWith[10];
char mimeType[50];
};
const struct esp_mail_mime_prop_t mimeinfo[esp_mail_file_extension_maxType] PROGMEM =
{
{".html", "text/html"},
{".htm", "text/html"},
{".css", "text/css"},
{".txt", "text/plain"},
{".js", "application/javascript"},
{".json", "application/json"},
{".png", "image/png"},
{".gif", "image/gif"},
{".jpg", "image/jpeg"},
{".ico", "image/x-icon"},
{".svg", "image/svg+xml"},
{".ttf", "application/x-font-ttf"},
{".otf", "application/x-font-opentype"},
{".woff", "application/font-woff"},
{".woff2", "application/font-woff2"},
{".eot", "application/vnd.ms-fontobject"},
{".sfnt", "application/font-sfnt"},
{".xml", "text/xml"},
{".pdf", "application/pdf"},
{".zip", "application/zip"},
{".gz", "application/x-gzip"},
{".appcache", "text/cache-manifest"},
{"", "application/octet-stream"}};
#endif

View File

@ -1,14 +1,13 @@
#ifndef RFC2047_CPP
#define RFC2047_CPP
#ifdef ESP32
#include "RFC2047.h"
RFC2047::RFC2047(){}
RFC2047_Decoder::RFC2047_Decoder() {}
RFC2047_Decoder::~RFC2047_Decoder() {}
void RFC2047::rfc2047Decode(char *d, const char *s, size_t dlen){
void RFC2047_Decoder::rfc2047Decode(char *d, const char *s, size_t dlen)
{
const char *p, *q;
size_t n;
@ -52,10 +51,10 @@ void RFC2047::rfc2047Decode(char *d, const char *s, size_t dlen){
d += n;
}
*d = 0;
}
void RFC2047::rfc2047DecodeWord(char *d, const char *s, size_t dlen){
void RFC2047_Decoder::rfc2047DecodeWord(char *d, const char *s, size_t dlen)
{
char *p = safe_strdup (s);
char *pp = p;
@ -154,8 +153,7 @@ void RFC2047::rfc2047DecodeWord(char *d, const char *s, size_t dlen){
return;
}
void *RFC2047::safe_calloc (size_t nmemb, size_t size)
void *RFC2047_Decoder::safe_calloc(size_t nmemb, size_t size)
{
void *p;
@ -169,7 +167,7 @@ void *RFC2047::safe_calloc (size_t nmemb, size_t size)
return p;
}
void *RFC2047::safe_malloc (unsigned int siz)
void *RFC2047_Decoder::safe_malloc(unsigned int siz)
{
void *p;
@ -183,7 +181,7 @@ void *RFC2047::safe_malloc (unsigned int siz)
return (p);
}
void RFC2047::safe_realloc (void **p, size_t siz)
void RFC2047_Decoder::safe_realloc(void **p, size_t siz)
{
void *r;
@ -213,7 +211,7 @@ void RFC2047::safe_realloc (void **p, size_t siz)
*p = r;
}
void RFC2047::safe_free (void *ptr)
void RFC2047_Decoder::safe_free(void *ptr)
{
void **p = (void **)ptr;
if (*p)
@ -223,7 +221,7 @@ void RFC2047::safe_free (void *ptr)
}
}
char *RFC2047::safe_strdup (const char *s)
char *RFC2047_Decoder::safe_strdup(const char *s)
{
char *p;
size_t l;
@ -235,6 +233,5 @@ char *RFC2047::safe_strdup (const char *s)
return (p);
}
#endif //ESP32
#endif //RFC2047_CPP

View File

@ -2,7 +2,6 @@
#ifndef RFC2047_H
#define RFC2047_H
#ifdef ESP32
#include <Arduino.h>
@ -47,10 +46,11 @@ __attribute__((used)) static int Index_64[128] = {
#define hexval(c) Index_hex[(unsigned int)(c)]
#define base64val(c) Index_64[(unsigned int)(c)]
class RFC2047{
class RFC2047_Decoder{
public:
RFC2047();
RFC2047_Decoder();
~RFC2047_Decoder();
void rfc2047Decode(char *d, const char *s, size_t dlen);
@ -65,6 +65,5 @@ class RFC2047{
};
#endif //ESP32
#endif //RFC2047_H

View File

@ -0,0 +1,247 @@
/*
* Customized version of ESP32 HTTPClient Library.
*
* v 1.1.1
*
* The MIT License (MIT)
* Copyright (c) 2021 K. Suwatchai (Mobizt)
*
* HTTPClient Arduino library for ESP32
*
* Copyright (c) 2015 Markus Sattler. All rights reserved.
* This file is part of the HTTPClient for Arduino.
* Port to ESP32 by Evandro Luis Copercini (2017),
* changed fingerprints to CA verification.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef ESP_Mail_HTTPClient32_CPP
#define ESP_Mail_HTTPClient32_CPP
#ifdef ESP32
#include "ESP_Mail_HTTPClient32.h"
ESP_Mail_HTTPClient32::ESP_Mail_HTTPClient32()
{
transportTraits = ESP_Mail_TransportTraitsPtr(new ESP_Mail_TLSTraits(nullptr));
_wcs = transportTraits->create();
}
ESP_Mail_HTTPClient32::~ESP_Mail_HTTPClient32()
{
if (_wcs)
{
_wcs->stop();
_wcs.reset(nullptr);
_wcs.release();
}
std::string().swap(_host);
std::string().swap(_caCertFile);
_cacert.reset(new char);
_cacert = nullptr;
transportTraits.reset(nullptr);
}
bool ESP_Mail_HTTPClient32::begin(const char *host, uint16_t port)
{
_host = host;
_port = port;
return true;
}
bool ESP_Mail_HTTPClient32::connected()
{
if (_wcs)
{
if (_secured)
return _wcs->connected();
else
return _wcs->_ns_connected();
}
return false;
}
bool ESP_Mail_HTTPClient32::send(const char *header)
{
if (!connected())
return false;
if (_secured)
return (_wcs->write(header, strlen(header)) == strlen(header));
else
return (_wcs->_ns_write(header, strlen(header)) == strlen(header));
}
int ESP_Mail_HTTPClient32::send(const char *header, const char *payload)
{
size_t size = strlen(payload);
if (strlen(header) > 0)
{
if (!connect(_secured))
{
return ESP_MAIL_ERROR_HTTPC_ERROR_CONNECTION_REFUSED;
}
if (!send(header))
{
return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_HEADER_FAILED;
}
}
if (size > 0)
{
if (_secured)
{
if (_wcs->write(&payload[0], size) != size)
return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED;
}
else
{
if (_wcs->_ns_write(&payload[0], size) != size)
return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED;
}
}
return 0;
}
WiFiClient *ESP_Mail_HTTPClient32::stream(void)
{
if (connected())
return _wcs.get();
return nullptr;
}
ESP_Mail_WCS32 *ESP_Mail_HTTPClient32::_stream(void)
{
if (connected())
return _wcs.get();
return nullptr;
}
size_t ESP_Mail_HTTPClient32::_ns_print(const char *buf)
{
size_t size = strlen(buf);
return _wcs->_ns_write(&buf[0], size);
}
size_t ESP_Mail_HTTPClient32::_ns_println(const char *buf)
{
size_t size = strlen(buf);
size_t wr = _wcs->_ns_write((const char *)&buf[0], size);
std::string s = "\r\n";
wr += _wcs->_ns_write(s.c_str(), s.length());
return wr;
}
bool ESP_Mail_HTTPClient32::connect(void)
{
return connect(false);
}
bool ESP_Mail_HTTPClient32::connect(bool secured)
{
_secured = secured;
if (connected())
{
if (_secured)
{
while (_wcs->available() > 0)
_wcs->read();
}
else
{
while (_wcs->_ns_available() > 0)
_wcs->_ns_read();
}
return true;
}
if (!transportTraits)
return false;
transportTraits->verify(*_wcs, _host.c_str(), !secured, _debugCallback);
if (!_wcs->connect(_host.c_str(), _port))
return false;
return connected();
}
void ESP_Mail_HTTPClient32::setDebugCallback(DebugMsgCallback cb)
{
_debugCallback = std::move(cb);
}
void ESP_Mail_HTTPClient32::setCACert(const char *caCert)
{
if (caCert)
{
transportTraits.reset(nullptr);
transportTraits = ESP_Mail_TransportTraitsPtr(new ESP_Mail_TLSTraits(caCert));
_certType = 1;
}
else
_certType = 0;
}
void ESP_Mail_HTTPClient32::setCertFile(const char *caCertFile, esp_mail_file_storage_type storageType)
{
if (strlen(caCertFile) > 0)
{
bool t = false;
_certType = 2;
if (storageType == esp_mail_file_storage_type::esp_mail_file_storage_type_flash)
t = SPIFFS.begin(true);
else if (storageType == esp_mail_file_storage_type::esp_mail_file_storage_type_sd)
t = SD.begin();
if (!t)
return;
File f;
if (storageType == esp_mail_file_storage_type::esp_mail_file_storage_type_flash)
{
if (SPIFFS.exists(caCertFile))
f = SPIFFS.open(caCertFile, FILE_READ);
}
else if (storageType == esp_mail_file_storage_type::esp_mail_file_storage_type_sd)
{
if (SD.exists(caCertFile))
f = SD.open(caCertFile, FILE_READ);
}
if (f)
{
size_t len = f.size();
_cacert.reset(new char);
_cacert = nullptr;
_cacert = std::unique_ptr<char>(new char[len]);
if (f.available())
f.readBytes(_cacert.get(), len);
f.close();
transportTraits.reset(nullptr);
transportTraits = ESP_Mail_TransportTraitsPtr(new ESP_Mail_TLSTraits(_cacert.get()));
}
}
}
#endif //ESP32
#endif //ESP_Mail_HTTPClient32_CPP

View File

@ -0,0 +1,179 @@
/*
* Customized version of ESP32 HTTPClient Library.
*
* v 1.1.1
*
* The MIT License (MIT)
* Copyright (c) 2021 K. Suwatchai (Mobizt)
*
* HTTPClient Arduino library for ESP32
*
* Copyright (c) 2015 Markus Sattler. All rights reserved.
* This file is part of the HTTPClient for Arduino.
* Port to ESP32 by Evandro Luis Copercini (2017),
* changed fingerprints to CA verification.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef ESP_Mail_HTTPClient32_H
#define ESP_Mail_HTTPClient32_H
#ifdef ESP32
#include <Arduino.h>
#include <WiFiClient.h>
#include <FS.h>
#include <SPIFFS.h>
#include <SD.h>
#include "ESP_Mail_WCS32.h"
#if __has_include(<WiFiEspAT.h>) || __has_include(<espduino.h>)
#error WiFi UART bridge was not supported.
#endif
#define ESP_MAIL_ERROR_HTTPC_ERROR_CONNECTION_REFUSED (-1)
#define ESP_MAIL_ERROR_HTTPC_ERROR_SEND_HEADER_FAILED (-2)
#define ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED (-3)
#define ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC 30
enum esp_mail_file_storage_type
{
esp_mail_file_storage_type_none,
esp_mail_file_storage_type_flash,
esp_mail_file_storage_type_sd,
esp_mail_file_storage_type_univ
};
class ESP_Mail_TransportTraits
{
public:
virtual ~ESP_Mail_TransportTraits() {}
virtual std::unique_ptr<ESP_Mail_WCS32> create()
{
return std::unique_ptr<ESP_Mail_WCS32>(new ESP_Mail_WCS32());
}
virtual bool
verify(ESP_Mail_WCS32 &client, const char *host, bool starttls, DebugMsgCallback cb)
{
return true;
}
};
class ESP_Mail_TLSTraits : public ESP_Mail_TransportTraits
{
public:
ESP_Mail_TLSTraits(const char *CAcert, const char *clicert = nullptr, const char *clikey = nullptr) : _cacert(CAcert), _clicert(clicert), _clikey(clikey) {}
std::unique_ptr<ESP_Mail_WCS32> create() override
{
return std::unique_ptr<ESP_Mail_WCS32>(new ESP_Mail_WCS32());
}
bool verify(ESP_Mail_WCS32 &client, const char *host, bool starttls, DebugMsgCallback cb) override
{
ESP_Mail_WCS32 &wcs = static_cast<ESP_Mail_WCS32 &>(client);
wcs.setCACert(_cacert);
wcs.setCertificate(_clicert);
wcs.setPrivateKey(_clikey);
wcs.setSTARTTLS(starttls);
wcs.setDebugCB(cb);
return true;
}
protected:
const char *_cacert;
const char *_clicert;
const char *_clikey;
};
typedef std::unique_ptr<ESP_Mail_TransportTraits> ESP_Mail_TransportTraitsPtr;
class ESP_Mail_HTTPClient32
{
public:
ESP_Mail_HTTPClient32();
~ESP_Mail_HTTPClient32();
/**
* Initialization of new http connection.
* \param host - Host name without protocols.
* \param port - Server's port.
* \return True as default.
* If no certificate string provided, use (const char*)NULL to CAcert param
*/
bool begin(const char *host, uint16_t port);
/**
* Check the http connection status.
* \return True if connected.
*/
bool connected();
/**
* Establish http connection if header provided and send it, send payload if provided.
* \param header - The header string (constant chars array).
* \param payload - The payload string (constant chars array), optional.
* \return http status code, Return zero if new http connection and header and/or payload sent
* with no error or no header and payload provided. If obly payload provided, no new http connection was established.
*/
int send(const char *header, const char *payload);
/**
* Send extra header without making new http connection (if send has been called)
* \param header - The header string (constant chars array).
* \return True if header sending success.
* Need to call send with header first.
*/
bool send(const char *header);
/**
* Get the WiFi client pointer.
* \return WiFi client pointer.
*/
WiFiClient *stream(void);
ESP_Mail_WCS32 *_stream(void);
size_t _ns_print(const char *buf);
size_t _ns_println(const char *buf);
int tcpTimeout = 40000;
bool connect(void);
bool connect(bool secured);
void setCACert(const char *caCert);
void setCertFile(const char *caCertFile, esp_mail_file_storage_type storageType);
void setDebugCallback(DebugMsgCallback cb);
bool _secured = true;
int _certType = -1;
std::string _caCertFile = "";
esp_mail_file_storage_type _caCertFileStoreageType = esp_mail_file_storage_type::esp_mail_file_storage_type_none;
protected:
DebugMsgCallback _debugCallback = NULL;
ESP_Mail_TransportTraitsPtr transportTraits;
std::unique_ptr<ESP_Mail_WCS32> _wcs;
std::unique_ptr<char> _cacert;
std::string _host = "";
uint16_t _port = 0;
};
#endif //ESP32
#endif //ESP_Mail_HTTPClient32_H

View File

@ -0,0 +1,553 @@
/*
*Customized WiFiClientSecure.cpp version 1.0.3
*
* The MIT License (MIT)
* Copyright (c) 2021 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.
*/
/*
WiFiClientSecure.cpp - Client Secure class for ESP32
Copyright (c) 2016 Hristo Gochkov All right reserved.
Additions Copyright (C) 2017 Evandro Luis Copercini.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ESP_Mail_WCS32_CPP
#define ESP_Mail_WCS32_CPP
#ifdef ESP32
#include "ESP_Mail_WCS32.h"
#include <lwip/sockets.h>
#include <lwip/netdb.h>
#include <errno.h>
#undef connect
#undef write
#undef read
ESP_Mail_WCS32::ESP_Mail_WCS32()
{
_connected = false;
sslclient = new esp_mail_ssl_ctx32;
ssl_init(sslclient);
sslclient->socket = -1;
sslclient->handshake_timeout = 120000;
_CA_cert = NULL;
_cert = NULL;
_private_key = NULL;
_pskIdent = NULL;
_psKey = NULL;
next = NULL;
}
ESP_Mail_WCS32::ESP_Mail_WCS32(int sock)
{
_connected = false;
_timeout = 0;
sslclient = new esp_mail_ssl_ctx32;
ssl_init(sslclient);
sslclient->socket = sock;
sslclient->handshake_timeout = 120000;
if (sock >= 0)
{
_connected = true;
}
_CA_cert = NULL;
_cert = NULL;
_private_key = NULL;
_pskIdent = NULL;
_psKey = NULL;
next = NULL;
}
ESP_Mail_WCS32::ESP_Mail_WCS32(bool secured)
{
_connected = false;
sslclient = new esp_mail_ssl_ctx32;
ssl_init(sslclient);
sslclient->socket = -1;
sslclient->handshake_timeout = 120000;
_secured = secured;
_CA_cert = NULL;
_cert = NULL;
_private_key = NULL;
_pskIdent = NULL;
_psKey = NULL;
next = NULL;
}
ESP_Mail_WCS32::~ESP_Mail_WCS32()
{
stop();
delete sslclient;
}
ESP_Mail_WCS32 &ESP_Mail_WCS32::operator=(const ESP_Mail_WCS32 &other)
{
stop();
sslclient->socket = other.sslclient->socket;
_connected = other._connected;
return *this;
}
void ESP_Mail_WCS32::stop()
{
if (sslclient->socket >= 0)
{
close(sslclient->socket);
sslclient->socket = -1;
_connected = false;
_peek = -1;
}
stop_ssl_socket(sslclient, _CA_cert, _cert, _private_key);
}
int ESP_Mail_WCS32::connect(IPAddress ip, uint16_t port)
{
if (_pskIdent && _psKey)
return connect(ip, port, _pskIdent, _psKey);
return connect(ip, port, _CA_cert, _cert, _private_key);
}
int ESP_Mail_WCS32::connect(IPAddress ip, uint16_t port, int32_t timeout)
{
_timeout = timeout;
return connect(ip, port);
}
int ESP_Mail_WCS32::connect(const char *host, uint16_t port)
{
if (_pskIdent && _psKey)
return connect(host, port, _pskIdent, _psKey);
return connect(host, port, _CA_cert, _cert, _private_key);
}
int ESP_Mail_WCS32::connect(const char *host, uint16_t port, int32_t timeout)
{
_timeout = timeout;
return connect(host, port);
}
int ESP_Mail_WCS32::connect(IPAddress ip, uint16_t port, const char *_CA_cert, const char *_cert, const char *_private_key)
{
return connect(ip.toString().c_str(), port, _CA_cert, _cert, _private_key);
}
int ESP_Mail_WCS32::connect(const char *host, uint16_t port, const char *_CA_cert, const char *_cert, const char *_private_key)
{
_host = host;
_port = port;
_withCert = true;
if (_timeout > 0)
{
sslclient->handshake_timeout = _timeout;
}
int ret = start_socket(sslclient, host, port, _timeout);
_lastError = ret;
if (ret < 0)
{
log_e("start_ssl_client: %d", ret);
stop();
return 0;
}
if (_secured)
{
ret = start_ssl_client(sslclient, host, port, _timeout, _CA_cert, _cert, _private_key, NULL, NULL);
_lastError = ret;
if (ret < 0)
{
log_e("start_ssl_client: %d", ret);
stop();
return 0;
}
}
_connected = true;
return 1;
}
int ESP_Mail_WCS32::connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey)
{
return connect(ip.toString().c_str(), port, _pskIdent, _psKey);
}
int ESP_Mail_WCS32::connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey)
{
_host = host;
_port = port;
_withCert = true;
log_v("start_ssl_client with PSK");
if (_timeout > 0)
{
sslclient->handshake_timeout = _timeout;
}
int ret = start_socket(sslclient, host, port, _timeout);
_lastError = ret;
if (ret < 0)
{
log_e("start_ssl_client: %d", ret);
stop();
return 0;
}
if (_secured)
{
ret = start_ssl_client(sslclient, host, port, _timeout, NULL, NULL, NULL, _pskIdent, _psKey);
_lastError = ret;
if (ret < 0)
{
log_e("start_ssl_client: %d", ret);
stop();
return 0;
}
}
_connected = true;
return 1;
}
int ESP_Mail_WCS32::peek()
{
if (_peek >= 0)
{
return _peek;
}
_peek = timedRead();
return _peek;
}
size_t ESP_Mail_WCS32::write(uint8_t data)
{
return write(&data, 1);
}
int ESP_Mail_WCS32::read()
{
uint8_t data = -1;
int res = read(&data, 1);
if (res < 0)
{
return res;
}
return data;
}
size_t ESP_Mail_WCS32::write(const uint8_t *buf, size_t size)
{
if (!_connected)
{
return 0;
}
int res = send_ssl_data(sslclient, buf, size);
if (res < 0)
{
stop();
res = 0;
}
return res;
}
int ESP_Mail_WCS32::read(uint8_t *buf, size_t size)
{
int peeked = 0;
int avail = available();
if ((!buf && size) || avail <= 0)
{
return -1;
}
if (!size)
{
return 0;
}
if (_peek >= 0)
{
buf[0] = _peek;
_peek = -1;
size--;
avail--;
if (!size || !avail)
{
return 1;
}
buf++;
peeked = 1;
}
int res = get_ssl_receive(sslclient, buf, size);
if (res < 0)
{
stop();
return peeked ? peeked : res;
}
return res + peeked;
}
int ESP_Mail_WCS32::available()
{
int peeked = (_peek >= 0);
if (!_connected)
{
return peeked;
}
int res = data_to_read(sslclient);
if (res < 0)
{
stop();
return peeked ? peeked : res;
}
return res + peeked;
}
uint8_t ESP_Mail_WCS32::connected()
{
uint8_t dummy = 0;
read(&dummy, 0);
return _connected;
}
void ESP_Mail_WCS32::setCACert(const char *rootCA)
{
_CA_cert = rootCA;
}
void ESP_Mail_WCS32::setCertificate(const char *client_ca)
{
_cert = client_ca;
}
void ESP_Mail_WCS32::setPrivateKey(const char *private_key)
{
_private_key = private_key;
}
void ESP_Mail_WCS32::setPreSharedKey(const char *pskIdent, const char *psKey)
{
_pskIdent = pskIdent;
_psKey = psKey;
}
bool ESP_Mail_WCS32::verify(const char *fp, const char *domain_name)
{
if (!sslclient)
return false;
return verify_ssl_fingerprint(sslclient, fp, domain_name);
}
char *ESP_Mail_WCS32::_streamLoad(Stream &stream, size_t size)
{
static char *dest = nullptr;
if (dest)
{
free(dest);
}
dest = (char *)malloc(size);
if (!dest)
{
return nullptr;
}
if (size != stream.readBytes(dest, size))
{
free(dest);
dest = nullptr;
}
return dest;
}
bool ESP_Mail_WCS32::loadCACert(Stream &stream, size_t size)
{
char *dest = _streamLoad(stream, size);
bool ret = false;
if (dest)
{
setCACert(dest);
ret = true;
}
return ret;
}
bool ESP_Mail_WCS32::loadCertificate(Stream &stream, size_t size)
{
char *dest = _streamLoad(stream, size);
bool ret = false;
if (dest)
{
setCertificate(dest);
ret = true;
}
return ret;
}
bool ESP_Mail_WCS32::loadPrivateKey(Stream &stream, size_t size)
{
char *dest = _streamLoad(stream, size);
bool ret = false;
if (dest)
{
setPrivateKey(dest);
ret = true;
}
return ret;
}
int ESP_Mail_WCS32::lastError(char *buf, const size_t size)
{
if (!_lastError)
{
return 0;
}
char error_buf[100];
mbedtls_strerror(_lastError, error_buf, 100);
snprintf(buf, size, "%s", error_buf);
return _lastError;
}
void ESP_Mail_WCS32::setHandshakeTimeout(unsigned long handshake_timeout)
{
sslclient->handshake_timeout = handshake_timeout * 1000;
}
void ESP_Mail_WCS32::setSTARTTLS(bool enable)
{
_secured = !enable;
}
void ESP_Mail_WCS32::setDebugCB(DebugMsgCallback cb)
{
sslclient->_debugCallback = std::move(cb);
}
int ESP_Mail_WCS32::_ns_available()
{
if (sslclient->socket < 0)
return false;
if (_rxBuf.length() == 0)
{
int bufLen = 1024;
char *tmp = new char[bufLen];
memset(tmp, 0, bufLen);
int ret = _ns_lwip_read(sslclient, tmp, bufLen);
if (ret > 0)
_rxBuf += tmp;
delete[] tmp;
}
int result = _rxBuf.length();
if (!result)
{
optimistic_yield(100);
}
return result;
}
size_t ESP_Mail_WCS32::_ns_write(const char *buf, size_t size)
{
if (sslclient->socket < 0 || !size)
return 0;
return _ns_lwip_write(sslclient, buf, size);
}
size_t ESP_Mail_WCS32::_ns_read(char *buf, size_t size)
{
if (_rxBuf.length() == 0)
return _ns_lwip_read(sslclient, buf, size);
else
{
size_t sz = size;
if (sz > _rxBuf.length())
sz = _rxBuf.length();
strncpy(buf, _rxBuf.c_str(), sz);
_rxBuf.erase(0, sz);
return sz;
}
}
int ESP_Mail_WCS32::_ns_read()
{
int c = -1;
if (_rxBuf.length() == 0)
{
char *buf = new char[2];
memset(buf, 0, 2);
int ret = _ns_lwip_read(sslclient, buf, 1);
if (ret > 0)
c = buf[0];
delete[] buf;
}
else
{
c = _rxBuf.c_str()[0];
_rxBuf.erase(0, 1);
}
return c;
}
uint8_t ESP_Mail_WCS32::_ns_connected()
{
return sslclient->socket >= 0;
}
bool ESP_Mail_WCS32::_ns_connect_ssl()
{
int ret = 0;
if (_withKey)
ret = start_ssl_client(sslclient, _host.c_str(), _port, _timeout, _CA_cert, _cert, _private_key, NULL, NULL);
else if (_withCert)
ret = start_ssl_client(sslclient, _host.c_str(), _port, _timeout, NULL, NULL, NULL, _pskIdent, _psKey);
_lastError = ret;
if (ret < 0)
{
log_e("start_ssl_client: %d", ret);
stop();
return 0;
}
return 1;
}
#endif //ESP32
#endif //WiFiClientSecureESP32_CPP

View File

@ -1,9 +1,9 @@
/*
*Customized WiFiClientSecure.h to support STARTTLS protocol, version 1.0.1
*Customized WiFiClientSecure.h version 1.0.3
*
* The MIT License (MIT)
* Copyright (c) 2019 K. Suwatchai (Mobizt)
* Copyright (c) 2021 K. Suwatchai (Mobizt)
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
@ -25,7 +25,7 @@
*/
/*
WiFiClientSecureESP32.h - Base class that provides Client SSL to ESP32
WiFiClientSecure.h - Base class that provides Client SSL to ESP32
Copyright (c) 2011 Adrian McEwen. All right reserved.
Additions Copyright (C) 2017 Evandro Luis Copercini.
@ -44,22 +44,22 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef WiFiClientSecureESP32_H
#define WiFiClientSecureESP32_H
#ifndef ESP_Mail_WCS32_H
#define ESP_Mail_WCS32_H
#ifdef ESP32
#include "Arduino.h"
#include "IPAddress.h"
#include <WiFi.h>
#include "ssl_client32.h"
#include "esp_mail_ssl_client32.h"
typedef void (*DebugMsgCallback)(const char *msg);
class WiFiClientSecureESP32 : public WiFiClient
class ESP_Mail_WCS32 : public WiFiClient
{
protected:
sslclient_context32 *sslclient;
esp_mail_ssl_ctx32 *sslclient;
int _lastError = 0;
int _peek = -1;
@ -72,11 +72,12 @@ protected:
DebugMsgCallback _debugCallback = NULL;
public:
WiFiClientSecureESP32 *next;
WiFiClientSecureESP32();
WiFiClientSecureESP32(int socket);
WiFiClientSecureESP32(bool starttls);
~WiFiClientSecureESP32();
friend class ESP_Mail_HTTPClient32;
ESP_Mail_WCS32 *next;
ESP_Mail_WCS32();
ESP_Mail_WCS32(int socket);
ESP_Mail_WCS32(bool secured);
~ESP_Mail_WCS32();
int connect(IPAddress ip, uint16_t port);
int connect(IPAddress ip, uint16_t port, int32_t timeout);
int connect(const char *host, uint16_t port);
@ -104,14 +105,20 @@ public:
bool loadPrivateKey(Stream &stream, size_t size);
bool verify(const char *fingerprint, const char *domain_name);
void setHandshakeTimeout(unsigned long handshake_timeout);
void setSTARTTLS(bool starttls);
void setSTARTTLS(bool enable);
void setDebugCB(DebugMsgCallback cb);
int _ns_available();
size_t _ns_write(const char *buf, size_t size);
size_t _ns_read(char *buf, size_t size);
int _ns_read();
uint8_t _ns_connected();
bool _ns_connect_ssl();
operator bool()
{
return connected();
}
WiFiClientSecureESP32 &operator=(const WiFiClientSecureESP32 &other);
ESP_Mail_WCS32 &operator=(const ESP_Mail_WCS32 &other);
bool operator==(const bool value)
{
return bool() == value;
@ -120,8 +127,8 @@ public:
{
return bool() != value;
}
bool operator==(const WiFiClientSecureESP32 &);
bool operator!=(const WiFiClientSecureESP32 &rhs)
bool operator==(const ESP_Mail_WCS32 &);
bool operator!=(const ESP_Mail_WCS32 &rhs)
{
return !this->operator==(rhs);
};
@ -133,6 +140,12 @@ public:
private:
char *_streamLoad(Stream &stream, size_t size);
bool _secured = true;
bool _withCert = false;
bool _withKey = false;
std::string _host = "";
std::string _rxBuf = "";
int _port;
//friend class WiFiServer;
using Print::write;
@ -140,6 +153,4 @@ private:
#endif //ESP32
#endif //WiFiClientSecureESP32_H
#endif //ESP_Mail_WCS32_H

View File

@ -1,8 +1,8 @@
/*
*Customized ssl_client.cpp to support STARTTLS protocol, version 1.0.3
*Customized ssl_client.cpp to support STARTTLS protocol, version 1.0.5
*
* The MIT License (MIT)
* Copyright (c) 2019 K. Suwatchai (Mobizt)
* Copyright (c) 2021 K. Suwatchai (Mobizt)
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
@ -31,8 +31,8 @@
* Additions Copyright (C) 2017 Evandro Luis Copercini, Apache 2.0 License.
*/
#ifndef SSL_CLIENT32_CPP
#define SSL_CLIENT32_CPP
#ifndef ESP_MAIL_SSL_CLIENT32_CPP
#define ESP_MAIL_SSL_CLIENT32_CPP
#ifdef ESP32
@ -46,10 +46,10 @@
#include <mbedtls/oid.h>
#include <algorithm>
#include <string>
#include "ssl_client32.h"
#include "WiFi.h"
#include "esp_mail_ssl_client32.h"
#include <WiFi.h>
const char *pers32 = "esp32-tls";
const char *_esp_mail_pers32 = "esp32-tls";
static int handle_error(int err)
{
@ -66,7 +66,7 @@ static int handle_error(int err)
return err;
}
void ssl_init(sslclient_context32 *ssl_client)
void ssl_init(esp_mail_ssl_ctx32 *ssl_client)
{
mbedtls_ssl_init(&ssl_client->ssl_ctx);
mbedtls_ssl_config_init(&ssl_client->ssl_conf);
@ -74,14 +74,12 @@ void ssl_init(sslclient_context32 *ssl_client)
mbedtls_net_init(&ssl_client->server_fd);
}
int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey)
int start_socket(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t port, int timeout)
{
char buf[512];
int ret, flags;
int enable = 1;
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_2, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_2);
log_v("Free internal heap before TLS %u", ESP.getFreeHeap());
@ -92,7 +90,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
if (ssl_client->socket < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_3, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_3);
log_e("ERROR opening socket");
return ssl_client->socket;
}
@ -101,7 +99,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
if (!WiFiGenericClass::hostByName(host, srv))
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_4, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_4);
return -1;
}
@ -112,7 +110,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
serv_addr.sin_port = htons(port);
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_5, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_5);
if (lwip_connect(ssl_client->socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0)
{
@ -124,48 +122,40 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable));
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable));
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_6, ssl_client);
}
else
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_7, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_7);
log_e("Connect to Server failed!");
return -1;
}
fcntl(ssl_client->socket, F_SETFL, fcntl(ssl_client->socket, F_GETFL, 0) | O_NONBLOCK);
if (ssl_client->starttls && (port == 25 || port == 587 || port == 143))
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_8, ssl_client);
if ((ret = starttlsHandshake(ssl_client, port)) != 0)
{
log_e("STARTTLS failed!");
return -1;
}
return ssl_client->socket;
}
int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey)
{
char buf[512];
int ret, flags;
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_9, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_9);
log_v("Seeding the random number generator");
mbedtls_entropy_init(&ssl_client->entropy_ctx);
ret = mbedtls_ctr_drbg_seed(&ssl_client->drbg_ctx, mbedtls_entropy_func,
&ssl_client->entropy_ctx, (const unsigned char *)pers32, strlen(pers32));
&ssl_client->entropy_ctx, (const unsigned char *)_esp_mail_pers32, strlen(_esp_mail_pers32));
if (ret < 0)
{
if (ssl_client->_debugCallback)
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
@ -176,7 +166,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
}
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_10, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_10);
log_v("Setting up the SSL/TLS structure...");
@ -189,7 +179,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
@ -204,7 +194,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
if (rootCABuff != NULL)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_11, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_11);
log_v("Loading CA cert");
mbedtls_x509_crt_init(&ssl_client->ca_cert);
mbedtls_ssl_conf_authmode(&ssl_client->ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
@ -217,7 +207,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
@ -229,13 +219,13 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
else if (pskIdent != NULL && psKey != NULL)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_12, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_12);
log_v("Setting up PSK");
// convert PSK from hex to binary
if ((strlen(psKey) & 1) != 0 || strlen(psKey) > 2 * MBEDTLS_PSK_MAX_LEN)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_13, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_13);
log_e("pre-shared key not valid hex or too long");
return -1;
}
@ -266,7 +256,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
}
// set mbedtls config
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_14, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_14);
ret = mbedtls_ssl_conf_psk(&ssl_client->ssl_conf, psk, psk_len,
(const unsigned char *)pskIdent, strlen(pskIdent));
if (ret != 0)
@ -275,7 +265,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
@ -299,7 +289,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
mbedtls_pk_init(&ssl_client->client_key);
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_15, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_15);
log_v("Loading CRT cert");
@ -310,7 +300,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
@ -320,7 +310,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
}
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_16, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_16);
log_v("Loading private key");
ret = mbedtls_pk_parse_key(&ssl_client->client_key, (const unsigned char *)cli_key, strlen(cli_key) + 1, NULL, 0);
@ -334,7 +324,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
}
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_17, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_17);
log_v("Setting hostname for TLS session...");
@ -345,7 +335,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
@ -362,7 +352,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
@ -375,7 +365,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
mbedtls_ssl_set_bio(&ssl_client->ssl_ctx, &ssl_client->socket, mbedtls_net_send, mbedtls_net_recv, NULL);
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_18, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_18);
log_v("Performing the SSL/TLS handshake...");
unsigned long handshake_start_time = millis();
@ -387,7 +377,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
@ -415,7 +405,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
}
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_19, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_19);
log_v("Verifying peer X.509 certificate...");
@ -424,7 +414,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
bzero(buf, sizeof(buf));
mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags);
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_20, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_20);
log_e("Failed to verify peer certificate! verification info: %s", buf);
stop_ssl_socket(ssl_client, rootCABuff, cli_cert, cli_key); //It's not safe continue.
return handle_error(ret);
@ -432,7 +422,7 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
else
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_21, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_21);
log_v("Certificate verified.");
}
@ -456,10 +446,10 @@ int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t
return ssl_client->socket;
}
void stop_ssl_socket(sslclient_context32 *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key)
void stop_ssl_socket(esp_mail_ssl_ctx32 *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_22, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_22);
log_v("Cleaning SSL connection.");
if (ssl_client->socket >= 0)
@ -474,7 +464,7 @@ void stop_ssl_socket(sslclient_context32 *ssl_client, const char *rootCABuff, co
mbedtls_entropy_free(&ssl_client->entropy_ctx);
}
int data_to_read(sslclient_context32 *ssl_client)
int data_to_read(esp_mail_ssl_ctx32 *ssl_client)
{
int ret, res;
ret = mbedtls_ssl_read(&ssl_client->ssl_ctx, NULL, 0);
@ -488,7 +478,7 @@ int data_to_read(sslclient_context32 *ssl_client)
char *buf = new char[512];
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, ESP32_SSL_CLIENT_STR_1);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
@ -501,7 +491,7 @@ int data_to_read(sslclient_context32 *ssl_client)
return res;
}
int send_ssl_data(sslclient_context32 *ssl_client, const uint8_t *data, uint16_t len)
int send_ssl_data(esp_mail_ssl_ctx32 *ssl_client, const uint8_t *data, uint16_t len)
{
log_v("Writing HTTP request..."); //for low level debug
@ -520,7 +510,7 @@ int send_ssl_data(sslclient_context32 *ssl_client, const uint8_t *data, uint16_t
return ret;
}
int get_ssl_receive(sslclient_context32 *ssl_client, uint8_t *data, int length)
int get_ssl_receive(esp_mail_ssl_ctx32 *ssl_client, uint8_t *data, int length)
{
//log_d( "Reading HTTP response..."); //for low level debug
@ -584,7 +574,7 @@ static bool matchName(const std::string &name, const std::string &domainName)
}
// Verifies certificate provided by the peer to match specified SHA256 fingerprint
bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char *fp, const char *domain_name)
bool verify_ssl_fingerprint(esp_mail_ssl_ctx32 *ssl_client, const char *fp, const char *domain_name)
{
// Convert hex string to byte array
uint8_t fingerprint_local[32];
@ -599,7 +589,7 @@ bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char *fp, con
if (pos > len - 2)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_23, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_23);
log_d("pos:%d len:%d fingerprint too short", pos, len);
return false;
}
@ -607,7 +597,7 @@ bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char *fp, con
if (!parseHexNibble(fp[pos], &high) || !parseHexNibble(fp[pos + 1], &low))
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_24, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_24);
log_d("pos:%d len:%d invalid hex sequence: %c%c", pos, len, fp[pos], fp[pos + 1]);
return false;
}
@ -621,7 +611,7 @@ bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char *fp, con
if (!crt)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_25, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_25);
log_d("could not fetch peer certificate");
return false;
}
@ -638,7 +628,7 @@ bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char *fp, con
if (memcmp(fingerprint_local, fingerprint_remote, 32))
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_26, ssl_client);
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_26);
log_d("fingerprint doesn't match");
return false;
}
@ -651,7 +641,7 @@ bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char *fp, con
}
// Checks if peer certificate has specified domain in CN or SANs
bool verify_ssl_dn(sslclient_context32 *ssl_client, const char *domain_name)
bool verify_ssl_dn(esp_mail_ssl_ctx32 *ssl_client, const char *domain_name)
{
log_d("domain name: '%s'", (domain_name) ? domain_name : "(null)");
std::string domain_name_str(domain_name);
@ -698,15 +688,13 @@ bool verify_ssl_dn(sslclient_context32 *ssl_client, const char *domain_name)
return false;
}
int starttlsHandshake(sslclient_context32 *ssl_client, int port)
int _ns_lwip_write(esp_mail_ssl_ctx32 *ssl_client, const char *buf, int bufLen)
{
return lwip_write(ssl_client->socket, buf, bufLen);
}
int ret = 0;
size_t msgLen = 100;
size_t bufLen = 512;
char *buf = new char[bufLen];
char *hMsg = new char[msgLen];
int _ns_lwip_read(esp_mail_ssl_ctx32 *ssl_client, char *buf, int bufLen)
{
fd_set readset;
fd_set writeset;
fd_set errset;
@ -723,127 +711,21 @@ int starttlsHandshake(sslclient_context32 *ssl_client, int port)
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = lwip_select(ssl_client->socket, &readset, &writeset, &errset, &tv);
if (ret < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_27, ssl_client);
goto starttls_exit;
}
ret = read(ssl_client->socket, buf, bufLen);
int ret = lwip_select(ssl_client->socket, &readset, &writeset, &errset, &tv);
if (ret < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_28, ssl_client);
goto starttls_exit;
}
else
{
if (ssl_client->_debugCallback)
ssl_client->_debugCallback(buf);
return ret;
return read(ssl_client->socket, buf, bufLen);
}
if (port == 587 || port == 25)
{
memset(hMsg, 0, msgLen);
strcpy_P(hMsg, ESP32_SSL_CLIENT_STR_29);
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_30, ssl_client);
ret = lwip_write(ssl_client->socket, hMsg, strlen(hMsg));
if (ret < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_31, ssl_client);
goto starttls_exit;
}
ret = lwip_select(ssl_client->socket, &readset, &writeset, &errset, &tv);
if (ret < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_32, ssl_client);
goto starttls_exit;
}
memset(buf, 0, bufLen);
ret = lwip_read(ssl_client->socket, buf, bufLen);
if (ret < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_33, ssl_client);
goto starttls_exit;
}
else
{
if (ssl_client->_debugCallback)
ssl_client->_debugCallback(buf);
}
}
memset(hMsg, 0, msgLen);
strcpy_P(hMsg, ESP32_SSL_CLIENT_STR_34);
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_35, ssl_client);
ret = lwip_write(ssl_client->socket, hMsg, strlen(hMsg));
if (ret < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_36, ssl_client);
goto starttls_exit;
}
ret = lwip_select(ssl_client->socket, &readset, &writeset, &errset, &tv);
if (ret < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_37, ssl_client);
goto starttls_exit;
}
memset(buf, 0, bufLen);
ret = lwip_read(ssl_client->socket, buf, bufLen);
if (ret < 0)
{
if (ssl_client->_debugCallback)
ESP32SSLClientDebugInfo(ESP32_SSL_CLIENT_STR_38, ssl_client);
goto starttls_exit;
}
else
{
if (ssl_client->_debugCallback)
ssl_client->_debugCallback(buf);
}
delete[] buf;
delete[] hMsg;
return 0;
starttls_exit:
delete[] buf;
delete[] hMsg;
return -1;
}
void ESP32SSLClientDebugInfo(PGM_P info, sslclient_context32 *ssl_client)
void ssl_client_debug_pgm_send_cb(esp_mail_ssl_ctx32 *ssl_client, PGM_P info)
{
size_t dbgInfoLen = strlen_P(info) + 1;
char *dbgInfo = new char[dbgInfoLen];
memset(dbgInfo, 0, dbgInfoLen);
strcpy_P(dbgInfo, info);
ssl_client->_debugCallback(dbgInfo);
delete[] dbgInfo;
}

View File

@ -0,0 +1,105 @@
/*
*Customized ssl_client.h to support STARTTLS protocol, version 1.0.5
*
* The MIT License (MIT)
* Copyright (c) 2021 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.
*/
/* Provide SSL/TLS functions to ESP32 with Arduino IDE
* by Evandro Copercini - 2017 - Apache 2.0 License
*/
#ifndef ESP_MAIL_SSL_CLIENT32_H
#define ESP_MAIL_SSL_CLIENT32_H
#ifdef ESP32
#include <mbedtls/platform.h>
#include <mbedtls/net.h>
#include <mbedtls/debug.h>
#include <mbedtls/ssl.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/error.h>
static const char esp_ssl_client_str_1[] PROGMEM = "! E: ";
static const char esp_ssl_client_str_2[] PROGMEM = "> C: starting socket";
static const char esp_ssl_client_str_3[] PROGMEM = "! E: opening socket";
static const char esp_ssl_client_str_4[] PROGMEM = "! E: could not get ip from host";
static const char esp_ssl_client_str_5[] PROGMEM = "> C: connecting to Server";
static const char esp_ssl_client_str_6[] PROGMEM = "> C: server connected";
static const char esp_ssl_client_str_7[] PROGMEM = "! E: connect to Server failed!";
static const char esp_ssl_client_str_8[] PROGMEM = "< S: ";
static const char esp_ssl_client_str_9[] PROGMEM = "> C: seeding the random number generator";
static const char esp_ssl_client_str_10[] PROGMEM = "> C: setting up the SSL/TLS structure";
static const char esp_ssl_client_str_11[] PROGMEM = "> C: loading CA cert";
static const char esp_ssl_client_str_12[] PROGMEM = "> C: setting up PSK";
static const char esp_ssl_client_str_13[] PROGMEM = "! E: pre-shared key not valid hex or too long";
static const char esp_ssl_client_str_14[] PROGMEM = "> C: set mbedtls config";
static const char esp_ssl_client_str_15[] PROGMEM = "> C: loading CRT cert";
static const char esp_ssl_client_str_16[] PROGMEM = "> C: loading private key";
static const char esp_ssl_client_str_17[] PROGMEM = "> C: setting hostname for TLS session";
static const char esp_ssl_client_str_18[] PROGMEM = "> C: performing the SSL handshaking";
static const char esp_ssl_client_str_19[] PROGMEM = "> C: verifying peer X.509 certificate";
static const char esp_ssl_client_str_20[] PROGMEM = "! E: failed to verify peer certificate!";
static const char esp_ssl_client_str_21[] PROGMEM = "> C: certificate verified";
static const char esp_ssl_client_str_22[] PROGMEM = "> C: cleaning SSL connection";
static const char esp_ssl_client_str_23[] PROGMEM = "!E: fingerprint too short";
static const char esp_ssl_client_str_24[] PROGMEM = "!E: invalid hex sequence";
static const char esp_ssl_client_str_25[] PROGMEM = "!E: could not fetch peer certificate";
static const char esp_ssl_client_str_26[] PROGMEM = "!E: fingerprint doesn't match";
typedef void (*DebugMsgCallback)(const char *msg);
typedef struct esp_mail_ssl_ctx32
{
int socket;
mbedtls_ssl_context ssl_ctx;
mbedtls_ssl_config ssl_conf;
mbedtls_net_context server_fd;
mbedtls_ctr_drbg_context drbg_ctx;
mbedtls_entropy_context entropy_ctx;
mbedtls_x509_crt ca_cert;
mbedtls_x509_crt client_cert;
mbedtls_pk_context client_key;
DebugMsgCallback _debugCallback;
unsigned long handshake_timeout;
} esp_mail_ssl_ctx32;
void ssl_init(esp_mail_ssl_ctx32 *ssl_client);
int start_socket(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t port, int timeout);
int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey);
void stop_ssl_socket(esp_mail_ssl_ctx32 *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key);
int data_to_read(esp_mail_ssl_ctx32 *ssl_client);
int send_ssl_data(esp_mail_ssl_ctx32 *ssl_client, const uint8_t *data, uint16_t len);
int get_ssl_receive(esp_mail_ssl_ctx32 *ssl_client, uint8_t *data, int length);
bool verify_ssl_fingerprint(esp_mail_ssl_ctx32 *ssl_client, const char *fp, const char *domain_name);
bool verify_ssl_dn(esp_mail_ssl_ctx32 *ssl_client, const char *domain_name);
int _ns_lwip_write(esp_mail_ssl_ctx32 *ssl_client, const char *buf, int bufLen);
int _ns_lwip_read(esp_mail_ssl_ctx32 *ssl_client, char *buf, int bufLen);
void ssl_client_debug_pgm_send_cb(esp_mail_ssl_ctx32 *ssl_client, PGM_P info);
#endif //ESP32
#endif //SSL_CLIENT32_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,200 @@
/*
Copy of BearSSLHelpers.h
WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries
- Mostly compatible with Arduino WiFi shield library and standard
WiFiClient/ServerSecure (except for certificate handling).
Copyright (c) 2018 Earle F. Philhower, III
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ESP_Mail_BearSSLHelpers_H
#define ESP_Mail_BearSSLHelpers_H
#ifdef ESP8266
#include <bearssl/bearssl.h>
#include <Updater.h>
// Internal opaque structures, not needed by user applications
namespace ESP_Mail_brssl
{
class public_key;
class private_key;
}; // namespace ESP_Mail_brssl
namespace ESP_Mail
{
// Holds either a single public RSA or EC key for use when BearSSL wants a pubkey.
// Copies all associated data so no need to keep input PEM/DER keys.
// All inputs can be either in RAM or PROGMEM.
class PublicKey
{
public:
PublicKey();
PublicKey(const char *pemKey);
PublicKey(const uint8_t *derKey, size_t derLen);
~PublicKey();
bool parse(const char *pemKey);
bool parse(const uint8_t *derKey, size_t derLen);
// Accessors for internal use, not needed by apps
bool isRSA() const;
bool isEC() const;
const br_rsa_public_key *getRSA() const;
const br_ec_public_key *getEC() const;
// Disable the copy constructor, we're pointer based
PublicKey(const PublicKey &that) = delete;
private:
ESP_Mail_brssl::public_key *_key;
};
// Holds either a single private RSA or EC key for use when BearSSL wants a secretkey.
// Copies all associated data so no need to keep input PEM/DER keys.
// All inputs can be either in RAM or PROGMEM.
class PrivateKey
{
public:
PrivateKey();
PrivateKey(const char *pemKey);
PrivateKey(const uint8_t *derKey, size_t derLen);
~PrivateKey();
bool parse(const char *pemKey);
bool parse(const uint8_t *derKey, size_t derLen);
// Accessors for internal use, not needed by apps
bool isRSA() const;
bool isEC() const;
const br_rsa_private_key *getRSA() const;
const br_ec_private_key *getEC() const;
// Disable the copy constructor, we're pointer based
PrivateKey(const PrivateKey &that) = delete;
private:
ESP_Mail_brssl::private_key *_key;
};
// Holds one or more X.509 certificates and associated trust anchors for
// use whenever BearSSL needs a cert or TA. May want to have multiple
// certs for things like a series of trusted CAs (but check the CertStore class
// for a more memory efficient way).
// Copies all associated data so no need to keep input PEM/DER certs.
// All inputs can be either in RAM or PROGMEM.
class ESP_Mail_X509List
{
public:
ESP_Mail_X509List();
ESP_Mail_X509List(const char *pemCert);
ESP_Mail_X509List(const uint8_t *derCert, size_t derLen);
~ESP_Mail_X509List();
bool append(const char *pemCert);
bool append(const uint8_t *derCert, size_t derLen);
// Accessors
size_t getCount() const
{
return _count;
}
const br_x509_certificate *getX509Certs() const
{
return _cert;
}
const br_x509_trust_anchor *getTrustAnchors() const
{
return _ta;
}
// Disable the copy constructor, we're pointer based
ESP_Mail_X509List(const ESP_Mail_X509List &that) = delete;
private:
size_t _count;
br_x509_certificate *_cert;
br_x509_trust_anchor *_ta;
};
// Opaque object which wraps the BearSSL SSL session to make repeated connections
// significantly faster. Completely optional.
class ESP_Mail_WCS;
class Session
{
friend class ESP_Mail_WCS;
public:
Session() { memset(&_session, 0, sizeof(_session)); }
private:
br_ssl_session_parameters *getSession() { return &_session; }
// The actual BearSSL ession information
br_ssl_session_parameters _session;
};
// Updater SHA256 hash and signature verification
class HashSHA256 : public UpdaterHashClass
{
public:
virtual void begin() override;
virtual void add(const void *data, uint32_t len) override;
virtual void end() override;
virtual int len() override;
virtual const void *hash() override;
virtual const unsigned char *oid() override;
private:
br_sha256_context _cc;
unsigned char _sha256[32];
};
class SigningVerifier : public UpdaterVerifyClass
{
public:
virtual uint32_t length() override;
virtual bool verify(UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) override;
public:
SigningVerifier(PublicKey *pubKey) { _pubKey = pubKey; }
private:
PublicKey *_pubKey;
};
/*
// Stack thunked versions of calls
extern "C" {
extern unsigned char *thunk_br_ssl_engine_recvapp_buf( const br_ssl_engine_context *cc, size_t *len);
extern void thunk_br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len);
extern unsigned char *thunk_br_ssl_engine_recvrec_buf( const br_ssl_engine_context *cc, size_t *len);
extern void thunk_br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len);
extern unsigned char *thunk_br_ssl_engine_sendapp_buf( const br_ssl_engine_context *cc, size_t *len);
extern void thunk_br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len);
extern unsigned char *thunk_br_ssl_engine_sendrec_buf( const br_ssl_engine_context *cc, size_t *len);
extern void thunk_br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len);
};
*/
}; // namespace ESP_Mail
#endif /* ESP8266 */
#endif /* ESP_Mail_BearSSLHelpers_H */

View File

@ -0,0 +1,238 @@
/*
Copy of CertStoreBearSSL.cpp - Library for Arduino ESP8266
Copyright (c) 2018 Earle F. Philhower, III
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ESP_Mail_CertStoreBearSSL_CPP
#define ESP_Mail_CertStoreBearSSL_CPP
#ifdef ESP8266
#include "ESP_Mail_CertStoreBearSSL.h"
#include <memory>
#ifdef DEBUG_ESP_SSL
#define DEBUG_BSSL(fmt, ...) DEBUG_ESP_PORT.printf_P((PGM_P)PSTR( "BSSL:" fmt), ## __VA_ARGS__)
#else
#define DEBUG_BSSL(...)
#endif
namespace ESP_Mail {
extern "C" {
// Callback for the x509 decoder
static void dn_append(void *ctx, const void *buf, size_t len) {
br_sha256_context *sha1 = (br_sha256_context*)ctx;
br_sha256_update(sha1, buf, len);
}
}
ESP_Mail_CertStore::~ESP_Mail_CertStore() {
free(_indexName);
free(_dataName);
}
ESP_Mail_CertStore::ESP_Mail_CertInfo ESP_Mail_CertStore::_preprocessCert(uint32_t length, uint32_t offset, const void *raw) {
ESP_Mail_CertStore::ESP_Mail_CertInfo ci;
// Clear the CertInfo
memset(&ci, 0, sizeof(ci));
// Process it using SHA256, same as the hashed_dn
br_x509_decoder_context *ctx = new br_x509_decoder_context;
br_sha256_context *sha256 = new br_sha256_context;
if (!ctx || !sha256) {
DEBUG_BSSL("CertStore::_preprocessCert: OOM\n");
return ci;
}
br_sha256_init(sha256);
br_x509_decoder_init(ctx, dn_append, sha256, nullptr, nullptr);
br_x509_decoder_push(ctx, (const void*)raw, length);
// Copy result to structure
br_sha256_out(sha256, &ci.sha256);
ci.length = length;
ci.offset = offset;
// Clean up allocated memory
delete sha256;
delete ctx;
// Return result
return ci;
}
// The certs.ar file is a UNIX ar format file, concatenating all the
// individual certificates into a single blob in a space-efficient way.
int ESP_Mail_CertStore::initCertStore(FS &fs, const char *indexFileName, const char *dataFileName) {
int count = 0;
uint32_t offset = 0;
_fs = &fs;
// In case initCertStore called multiple times, don't leak old filenames
free(_indexName);
free(_dataName);
// No strdup_P, so manually do it
_indexName = (char *)malloc(strlen_P(indexFileName) + 1);
_dataName = (char *)malloc(strlen_P(dataFileName) + 1);
if (!_indexName || !_dataName) {
free(_indexName);
free(_dataName);
return 0;
}
memcpy_P(_indexName, indexFileName, strlen_P(indexFileName) + 1);
memcpy_P(_dataName, dataFileName, strlen_P(dataFileName) + 1);
File index = _fs->open(_indexName, "w");
if (!index) {
return 0;
}
File data = _fs->open(_dataName, "r");
if (!data) {
index.close();
return 0;
}
uint8_t magic[8];
if (data.read(magic, sizeof(magic)) != sizeof(magic) ||
memcmp(magic, "!<arch>\n", sizeof(magic)) ) {
data.close();
index.close();
return 0;
}
offset += sizeof(magic);
while (true) {
uint8_t fileHeader[60];
// 0..15 = filename in ASCII
// 48...57 = length in decimal ASCII
uint32_t length;
if (data.read(fileHeader, sizeof(fileHeader)) != sizeof(fileHeader)) {
break;
}
offset += sizeof(fileHeader);
fileHeader[58] = 0;
if (1 != sscanf((char *)(fileHeader + 48), "%d", &length) || !length) {
break;
}
void *raw = malloc(length);
if (!raw) {
break;
}
if (data.read((uint8_t *)raw, length) != length) {
free(raw);
break;
}
// If the filename starts with "//" then this is a rename file, skip it
if (fileHeader[0] != '/' || fileHeader[1] != '/') {
ESP_Mail_CertStore::ESP_Mail_CertInfo ci = _preprocessCert(length, offset, raw);
if (index.write((uint8_t *)&ci, sizeof(ci)) != (ssize_t)sizeof(ci)) {
free(raw);
break;
}
count++;
}
offset += length;
free(raw);
if (offset & 1) {
uint8_t x;
data.read(&x, 1);
offset++;
}
}
data.close();
index.close();
return count;
}
void ESP_Mail_CertStore::installCertStore(br_x509_minimal_context *ctx) {
br_x509_minimal_set_dynamic(ctx, (void*)this, findHashedTA, freeHashedTA);
}
const br_x509_trust_anchor *ESP_Mail_CertStore::findHashedTA(void *ctx, void *hashed_dn, size_t len) {
ESP_Mail_CertStore *cs = static_cast<ESP_Mail_CertStore*>(ctx);
ESP_Mail_CertStore::ESP_Mail_CertInfo ci;
if (!cs || len != sizeof(ci.sha256) || !cs->_indexName || !cs->_dataName || !cs->_fs) {
return nullptr;
}
File index = cs->_fs->open(cs->_indexName, "r");
if (!index) {
return nullptr;
}
while (index.read((uint8_t *)&ci, sizeof(ci)) == sizeof(ci)) {
if (!memcmp(ci.sha256, hashed_dn, sizeof(ci.sha256))) {
index.close();
uint8_t *der = (uint8_t*)malloc(ci.length);
if (!der) {
return nullptr;
}
File data = cs->_fs->open(cs->_dataName, "r");
if (!data) {
free(der);
return nullptr;
}
if (!data.seek(ci.offset, SeekSet)) {
data.close();
free(der);
return nullptr;
}
if (data.read((uint8_t *)der, ci.length) != ci.length) {
free(der);
return nullptr;
}
data.close();
cs->_x509 = new ESP_Mail_X509List(der, ci.length);
free(der);
if (!cs->_x509) {
DEBUG_BSSL("CertStore::findHashedTA: OOM\n");
return nullptr;
}
br_x509_trust_anchor *ta = (br_x509_trust_anchor*)cs->_x509->getTrustAnchors();
memcpy(ta->dn.data, ci.sha256, sizeof(ci.sha256));
ta->dn.len = sizeof(ci.sha256);
return ta;
}
}
index.close();
return nullptr;
}
void ESP_Mail_CertStore::freeHashedTA(void *ctx, const br_x509_trust_anchor *ta) {
ESP_Mail_CertStore *cs = static_cast<ESP_Mail_CertStore*>(ctx);
(void) ta; // Unused
delete cs->_x509;
cs->_x509 = nullptr;
}
}
#endif /* ESP8266 */
#endif /* ESP_Mail_CertStoreBearSSL_CPP */

View File

@ -0,0 +1,72 @@
/*
Copy of CertStoreBearSSL.h - Library for Arduino ESP8266
Copyright (c) 2018 Earle F. Philhower, III
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ESP_Mail_CertStoreBearSSL_H
#define ESP_Mail_CertStoreBearSSL_H
#ifdef ESP8266
#include <Arduino.h>
#include "ESP_Mail_BearSSLHelpers.h"
#include <bearssl/bearssl.h>
#include <FS.h>
// Base class for the certificate stores, which allow use
// of a large set of certificates stored on FS or SD card to
// be dynamically used when validating a X509 certificate
namespace ESP_Mail {
class ESP_Mail_CertStore {
public:
ESP_Mail_CertStore() { };
~ESP_Mail_CertStore();
// Set the file interface instances, do preprocessing
int initCertStore(FS &fs, const char *indexFileName, const char *dataFileName);
// Installs the cert store into the X509 decoder (normally via static function callbacks)
void installCertStore(br_x509_minimal_context *ctx);
protected:
FS *_fs = nullptr;
char *_indexName = nullptr;
char *_dataName = nullptr;
ESP_Mail_X509List *_x509 = nullptr;
// These need to be static as they are callbacks from BearSSL C code
static const br_x509_trust_anchor *findHashedTA(void *ctx, void *hashed_dn, size_t len);
static void freeHashedTA(void *ctx, const br_x509_trust_anchor *ta);
// The binary format of the index file
class ESP_Mail_CertInfo {
public:
uint8_t sha256[32];
uint32_t offset;
uint32_t length;
};
static ESP_Mail_CertInfo _preprocessCert(uint32_t length, uint32_t offset, const void *raw);
};
};
#endif /* ESP8266 */
#endif /* ESP_Mail_CertStoreBearSSL_H */

View File

@ -0,0 +1,277 @@
/*
* HTTP Client for ESP8266 wrapper v1.0.1
*
* The MIT License (MIT)
* Copyright (c) 2021 K. Suwatchai (Mobizt)
*
*
* Permission is hereby granted, free of charge, to any person returning 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.
*/
#ifndef ESP_Mail_HTTPClient_CPP
#define ESP_Mail_HTTPClient_CPP
#ifdef ESP8266
#include "ESP_Mail_HTTPClient.h"
ESP_Mail_HTTPClient::ESP_Mail_HTTPClient()
{
}
ESP_Mail_HTTPClient::~ESP_Mail_HTTPClient()
{
if (_wcs)
{
_wcs->stop();
_wcs.reset(nullptr);
_wcs.release();
}
std::string().swap(_host);
std::string().swap(_caCertFile);
_cacert.reset(new char);
_cacert = nullptr;
}
bool ESP_Mail_HTTPClient::begin(const char *host, uint16_t port)
{
if (strcmp(_host.c_str(), host) != 0)
mflnChecked = false;
_host = host;
_port = port;
//probe for fragmentation support at the specified size
if (!mflnChecked)
{
fragmentable = _wcs->probeMaxFragmentLength(_host.c_str(), _port, chunkSize);
if (fragmentable)
{
_bsslRxSize = chunkSize;
_bsslTxSize = chunkSize;
_wcs->setBufferSizes(_bsslRxSize, _bsslTxSize);
}
mflnChecked = true;
}
if (!fragmentable)
_wcs->setBufferSizes(maxRXBufSize / rxBufDivider, maxTXBufSize / txBufDivider);
return true;
}
bool ESP_Mail_HTTPClient::connected()
{
if (_wcs)
{
if (_secured)
return _wcs->connected();
else
return _wcs->_ns_connected();
}
return false;
}
bool ESP_Mail_HTTPClient::send(const char *header)
{
if (!connected())
return false;
if (_secured)
return (_wcs->write((uint8_t *)header, strlen(header)) == strlen(header));
else
return (_wcs->_ns_write((uint8_t *)header, strlen(header)) == strlen(header));
}
int ESP_Mail_HTTPClient::send(const char *header, const char *payload)
{
size_t size = strlen(payload);
if (strlen(header) > 0)
{
if (!connect(_secured))
{
return ESP_MAIL_ERROR_HTTPC_ERROR_CONNECTION_REFUSED;
}
if (!send(header))
{
return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_HEADER_FAILED;
}
}
if (size > 0)
{
if (_secured)
{
if (_wcs->write((uint8_t *)&payload[0], size) != size)
return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED;
}
else
{
if (_wcs->_ns_write((uint8_t *)&payload[0], size) != size)
return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED;
}
}
return 0;
}
WiFiClient *ESP_Mail_HTTPClient::stream(void)
{
if (connected())
return _wcs.get();
return nullptr;
}
ESP_Mail::ESP_Mail_WCS *ESP_Mail_HTTPClient::_stream(void)
{
if (connected())
return _wcs.get();
return nullptr;
}
size_t ESP_Mail_HTTPClient::_ns_print(const char *buf)
{
size_t size = strlen(buf);
return _wcs->_ns_write((uint8_t *)&buf[0], size);
}
size_t ESP_Mail_HTTPClient::_ns_println(const char *buf)
{
size_t size = strlen(buf);
size_t wr = _wcs->_ns_write((uint8_t *)&buf[0], size);
std::string s = "\r\n";
wr += _wcs->_ns_write((uint8_t *)s.c_str(), s.length());
return wr;
}
bool ESP_Mail_HTTPClient::connect(bool secured)
{
_secured = secured;
if (connected())
{
if (_secured)
{
while (_wcs->available() > 0)
_wcs->read();
}
else
{
while (_wcs->_ns_available() > 0)
_wcs->_ns_read();
}
return true;
}
_wcs->setStartTLS(!_secured);
if (!_wcs->connect(_host.c_str(), _port))
return false;
return connected();
}
void ESP_Mail_HTTPClient::setCACert(const char *caCert)
{
#ifndef USING_AXTLS
_wcs->setBufferSizes(_bsslRxSize, _bsslTxSize);
#endif
if (caCert)
{
#ifndef USING_AXTLS
_wcs->setTrustAnchors(new ESP_Mail::ESP_Mail_X509List(caCert));
#else
_wcs->setCACert_P(caCert, strlen_P(caCert));
#endif
_certType = 1;
}
else
{
#ifndef USING_AXTLS
_wcs->setInsecure();
#endif
_certType = 0;
}
_wcs->setNoDelay(true);
}
void ESP_Mail_HTTPClient::setCertFile(const char *caCertFile, esp_mail_file_storage_type storageType, uint8_t sdPin)
{
#ifndef USING_AXTLS
_sdPin = sdPin;
_wcs->setBufferSizes(_bsslRxSize, _bsslTxSize);
if (_clockReady && strlen(caCertFile) > 0)
{
if (storageType == 0)
{
bool t = FLASH_FS.begin();
if (t)
{
fs::File f;
if (FLASH_FS.exists(caCertFile))
{
f = FLASH_FS.open(caCertFile, "r");
size_t len = f.size();
uint8_t *der = new uint8_t[len];
if (f.available())
f.read(der, len);
f.close();
_wcs->setTrustAnchors(new ESP_Mail::ESP_Mail_X509List(der, len));
delete[] der;
}
}
}
else
{
bool t = SD.begin(_sdPin);
if (t)
{
File f;
if (SD.exists(caCertFile))
{
f = SD.open(caCertFile, FILE_READ);
size_t len = f.size();
uint8_t *der = new uint8_t[len];
if (f.available())
f.read(der, len);
f.close();
_wcs->setTrustAnchors(new ESP_Mail::ESP_Mail_X509List(der, len));
delete[] der;
}
}
}
_certType = 2;
}
#endif
_wcs->setNoDelay(true);
}
#endif /* ESP8266 */
#endif /* ESP_Mail_HTTPClient_CPP */

View File

@ -0,0 +1,151 @@
/*
* HTTP Client for ESP8266 wrapper v1.0.1
*
* The MIT License (MIT)
* Copyright (c) 2021 K. Suwatchai (Mobizt)
*
*
* Permission is hereby granted, free of charge, to any person returning 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.
*/
#ifndef ESP_Mail_HTTPClient_H
#define ESP_Mail_HTTPClient_H
#ifdef ESP8266
//ARDUINO_ESP8266_GIT_VER
//2.6.2 0xbc204a9b
//2.6.1 0x482516e3
//2.6.0 0x643ec203
//2.5.2 0x8b899c12
//2.5.1 0xac02aff5
//2.5.0 0x951aeffa
//2.5.0-beta3 0x21db8fc9
//2.5.0-beta2 0x0fd86a07
//2.5.0-beta1 0x9c1e03a1
//2.4.2 0xbb28d4a3
//2.4.1 0x614f7c32
//2.4.0 0x4ceabea9
//2.4.0-rc2 0x0c897c37
//2.4.0-rc1 0xf6d232f1
#include <Arduino.h>
#include <core_version.h>
#include <time.h>
#ifndef ARDUINO_ESP8266_GIT_VER
#error Your ESP8266 Arduino Core SDK is outdated, please update. From Arduino IDE go to Boards Manager and search 'esp8266' then select the latest version.
#endif
#include <WiFiClient.h>
#if ARDUINO_ESP8266_GIT_VER != 0xf6d232f1 && ARDUINO_ESP8266_GIT_VER != 0x0c897c37 && ARDUINO_ESP8266_GIT_VER != 0x4ceabea9 && ARDUINO_ESP8266_GIT_VER != 0x614f7c32 && ARDUINO_ESP8266_GIT_VER != 0xbb28d4a3
#include "ESP_Mail_WCS.h"
#include "ESP_Mail_BearSSLHelpers.h"
#define ESP_MAIL_SSL_CLIENT ESP_Mail::ESP_Mail_WCS
#else
#error Please update the ESP8266 Arduino Core SDK to latest version.
#endif
#define FS_NO_GLOBALS
#include <FS.h>
#include <SD.h>
#include "extras/ESP_Mail_Client_FS.h"
#ifdef USE_LITTLEFS
#include <LittleFS.h>
#define FLASH_FS LittleFS
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#define FLASH_FS SPIFFS
#endif
#if __has_include(<WiFiEspAT.h>) || __has_include(<espduino.h>)
#error WiFi UART bridge was not supported.
#endif
#define ESP_MAIL_ERROR_HTTPC_ERROR_CONNECTION_REFUSED (-1)
#define ESP_MAIL_ERROR_HTTPC_ERROR_SEND_HEADER_FAILED (-2)
#define ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED (-3)
#define ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC 30
enum esp_mail_file_storage_type
{
esp_mail_file_storage_type_none,
esp_mail_file_storage_type_flash,
esp_mail_file_storage_type_sd,
esp_mail_file_storage_type_univ
};
class ESP_Mail_HTTPClient
{
public:
ESP_Mail_HTTPClient();
~ESP_Mail_HTTPClient();
bool begin(const char *host, uint16_t port);
bool connected(void);
int send(const char *header, const char *payload);
bool send(const char *header);
WiFiClient *stream(void);
ESP_Mail::ESP_Mail_WCS *_stream(void);
size_t _ns_print(const char *buf);
size_t _ns_println(const char *buf);
void setCACert(const char *caCert);
void setCertFile(const char *caCertFile, esp_mail_file_storage_type storageType, uint8_t sdPin);
bool connect(bool secured);
int _certType = -1;
std::string _caCertFile = "";
esp_mail_file_storage_type _caCertFileStoreageType = esp_mail_file_storage_type::esp_mail_file_storage_type_none;
uint16_t tcpTimeout = 40000;
uint8_t _sdPin = 15;
bool _clockReady = false;
uint16_t _bsslRxSize = 1024;
uint16_t _bsslTxSize = 1024;
bool fragmentable = false;
int chunkSize = 1024;
int maxRXBufSize = 16384; //SSL full supported 16 kB
int maxTXBufSize = 16384;
bool mflnChecked = false;
int rxBufDivider = maxRXBufSize / chunkSize;
int txBufDivider = maxRXBufSize / chunkSize;
;
private:
std::unique_ptr<ESP_MAIL_SSL_CLIENT> _wcs = std::unique_ptr<ESP_MAIL_SSL_CLIENT>(new ESP_MAIL_SSL_CLIENT());
std::unique_ptr<char> _cacert;
std::string _host = "";
uint16_t _port = 0;
bool _secured = true;
};
#endif /* ESP8266 */
#endif /* ESP_Mail_HTTPClient_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,306 @@
/*
Customized version of WiFiClientSecure.h
WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries
- Mostly compatible with Arduino WiFi shield library and standard
WiFiClient/ServerSecure (except for certificate handling).
Copyright (c) 2018 Earle F. Philhower, III
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ESP_Mail_WCS_H
#define ESP_Mail_WCS_H
#ifdef ESP8266
#include <vector>
#include <WiFiClient.h>
#include <bearssl/bearssl.h>
#include "ESP_Mail_BearSSLHelpers.h"
#include "ESP_Mail_CertStoreBearSSL.h"
namespace ESP_Mail {
//#define DEBUG_ESP_SSL
//#define DEBUG_ESP_PORT Serial
struct br_x509_insecure_context;
class ESP_Mail_WCS : public WiFiClient
{
public:
ESP_Mail_WCS();
ESP_Mail_WCS(const ESP_Mail_WCS &rhs);
~ESP_Mail_WCS() override;
ESP_Mail_WCS& operator=(const ESP_Mail_WCS&) = default; // The shared-ptrs handle themselves automatically
int connect(IPAddress ip, uint16_t port) override;
int connect(const String& host, uint16_t port) override;
int connect(const char* name, uint16_t port) override;
uint8_t connected() override;
size_t write(const uint8_t *buf, size_t size) override;
size_t write_P(PGM_P buf, size_t size) override;
size_t write(const char *buf) {
return write((const uint8_t*)buf, strlen(buf));
}
size_t write_P(const char *buf) {
return write_P((PGM_P)buf, strlen_P(buf));
}
size_t write(Stream& stream); // Note this is not virtual
int read(uint8_t *buf, size_t size) override;
int available() override;
int read() override;
int peek() override;
size_t peekBytes(uint8_t *buffer, size_t length) override;
bool flush(unsigned int maxWaitMs);
bool stop(unsigned int maxWaitMs);
void flush() override { (void)flush(0); }
void stop() override { (void)stop(0); }
// Allow sessions to be saved/restored automatically to a memory area
void setSession(Session *session) { _session = session; }
// Don't validate the chain, just accept whatever is given. VERY INSECURE!
void setInsecure() {
_clearAuthenticationSettings();
_use_insecure = true;
}
// Assume a given public key, don't validate or use cert info at all
void setKnownKey(const PublicKey *pk, unsigned usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN) {
_clearAuthenticationSettings();
_knownkey = pk;
_knownkey_usages = usages;
}
// Only check SHA1 fingerprint of certificate
bool setFingerprint(const uint8_t fingerprint[20]) {
_clearAuthenticationSettings();
_use_fingerprint = true;
memcpy_P(_fingerprint, fingerprint, 20);
return true;
}
bool setFingerprint(const char *fpStr);
// Accept any certificate that's self-signed
void allowSelfSignedCerts() {
_clearAuthenticationSettings();
_use_self_signed = true;
}
// Install certificates of trusted CAs or specific site
void setTrustAnchors(const ESP_Mail_X509List *ta) {
_clearAuthenticationSettings();
_ta = ta;
}
// In cases when NTP is not used, app must set a time manually to check cert validity
void setX509Time(time_t now) {
_now = now;
}
// Install a client certificate for this connection, in case the server requires it (i.e. MQTT)
void setClientRSACert(const ESP_Mail_X509List *cert, const PrivateKey *sk);
void setClientECCert(const ESP_Mail_X509List *cert, const PrivateKey *sk,
unsigned allowed_usages, unsigned cert_issuer_key_type);
// Sets the requested buffer size for transmit and receive
void setBufferSizes(int recv, int xmit);
// Returns whether MFLN negotiation for the above buffer sizes succeeded (after connection)
int getMFLNStatus() {
return connected() && br_ssl_engine_get_mfln_negotiated(_eng);
}
// Return an error code and possibly a text string in a passed-in buffer with last SSL failure
int getLastSSLError(char *dest = NULL, size_t len = 0);
// Attach a preconfigured certificate store
void setCertStore(ESP_Mail_CertStore *certStore) {
_certStore = certStore;
}
// Select specific ciphers (i.e. optimize for speed over security)
// These may be in PROGMEM or RAM, either will run properly
bool setCiphers(const uint16_t *cipherAry, int cipherCount);
bool setCiphers(std::vector<uint16_t> list);
bool setCiphersLessSecure(); // Only use the limited set of RSA ciphers without EC
// Check for Maximum Fragment Length support for given len before connection (possibly insecure)
static bool probeMaxFragmentLength(IPAddress ip, uint16_t port, uint16_t len);
static bool probeMaxFragmentLength(const char *hostname, uint16_t port, uint16_t len);
static bool probeMaxFragmentLength(const String& host, uint16_t port, uint16_t len);
void setStartTLS(bool enable);
size_t _ns_write(uint8_t b);
size_t _ns_write(const uint8_t *buf, size_t size);
size_t _ns_write(Stream &stream, size_t unused);
size_t _ns_write(Stream &stream);
size_t _ns_write_P(PGM_P buf, size_t size);
int _ns_available();
int _ns_read();
int _ns_read(uint8_t *buf, size_t size);
int _ns_peek();
size_t _ns_peekBytes(uint8_t *buffer, size_t length);
uint8_t _ns_connected();
bool _ns_connect_ssl();
////////////////////////////////////////////////////
// AxTLS API deprecated warnings to help upgrading
bool setCACert(const uint8_t* pk, size_t size) ;
bool setCertificate(const uint8_t* pk, size_t size) ;
bool setPrivateKey(const uint8_t* pk, size_t size) ;
bool loadCACert(Stream& stream, size_t size) ;
bool loadCertificate(Stream& stream, size_t size) ;
bool loadPrivateKey(Stream& stream, size_t size) ;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
bool setCACert_P(PGM_VOID_P pk, size_t size) {
return setCACert((const uint8_t *)pk, size);
}
bool setCertificate_P(PGM_VOID_P pk, size_t size) {
return setCertificate((const uint8_t *)pk, size);
}
bool setPrivateKey_P(PGM_VOID_P pk, size_t size) {
return setPrivateKey((const uint8_t *)pk, size);
}
#pragma GCC diagnostic pop
template<typename TFile>
bool loadCertificate(TFile& file) {
return loadCertificate(file, file.size());
}
template<typename TFile>
bool loadPrivateKey(TFile& file) {
return loadPrivateKey(file, file.size());
}
template<typename TFile>
bool loadCACert(TFile& file) {
return loadCACert(file, file.size());
}
bool verify(const char* fingerprint, const char* domain_name) {
(void)fingerprint;
(void)domain_name;
return connected();
}
bool verifyCertChain(const char* domain_name) {
(void)domain_name;
return connected();
}
// AxTLS API deprecated section end
/////////////////////////////////////
protected:
bool _connectSSL(const char *hostName); // Do initial SSL handshake
private:
void _clear();
void _clearAuthenticationSettings();
// Only one of the following two should ever be != nullptr!
std::shared_ptr<br_ssl_client_context> _sc;
std::shared_ptr<br_ssl_server_context> _sc_svr;
inline bool ctx_present() {
return (_sc != nullptr) || (_sc_svr != nullptr);
}
br_ssl_engine_context *_eng; // &_sc->eng, to allow for client or server contexts
std::shared_ptr<br_x509_minimal_context> _x509_minimal;
std::shared_ptr<struct br_x509_insecure_context> _x509_insecure;
std::shared_ptr<br_x509_knownkey_context> _x509_knownkey;
std::shared_ptr<unsigned char> _iobuf_in;
std::shared_ptr<unsigned char> _iobuf_out;
time_t _now;
const ESP_Mail_X509List *_ta;
ESP_Mail_CertStore *_certStore;
int _iobuf_in_size;
int _iobuf_out_size;
bool _handshake_done;
bool _oom_err;
bool _secured;
std::string _host_name;
// AXTLS compatibility shim elements:
// AXTLS managed memory for certs and keys, while BearSSL assumes
// the app manages these. Use this local storage for holding the
// BearSSL created objects in a shared form.
std::shared_ptr<ESP_Mail_X509List> _axtls_ta;
std::shared_ptr<ESP_Mail_X509List> _axtls_chain;
std::shared_ptr<PrivateKey> _axtls_sk;
// Optional storage space pointer for session parameters
// Will be used on connect and updated on close
Session *_session;
bool _use_insecure;
bool _use_fingerprint;
uint8_t _fingerprint[20];
bool _use_self_signed;
const PublicKey *_knownkey;
unsigned _knownkey_usages;
// Custom cipher list pointer or NULL if default
std::shared_ptr<uint16_t> _cipher_list;
uint8_t _cipher_cnt;
unsigned char *_recvapp_buf;
size_t _recvapp_len;
bool _clientConnected(); // Is the underlying socket alive?
void _freeSSL();
int _run_until(unsigned target, bool blocking = true);
size_t _write(const uint8_t *buf, size_t size, bool pmem);
bool _wait_for_handshake(); // Sets and return the _handshake_done after connecting
// Optional client certificate
const ESP_Mail_X509List *_chain;
const PrivateKey *_sk;
unsigned _allowed_usages;
unsigned _cert_issuer_key_type;
// Methods for handling server.available() call which returns a client connection.
friend class WiFiServerSecure; // Server needs to access these constructors
ESP_Mail_WCS(ClientContext *client, const ESP_Mail_X509List *chain, unsigned cert_issuer_key_type,
const PrivateKey *sk, int iobuf_in_size, int iobuf_out_size, const ESP_Mail_X509List *client_CA_ta);
ESP_Mail_WCS(ClientContext* client, const ESP_Mail_X509List *chain, const PrivateKey *sk,
int iobuf_in_size, int iobuf_out_size, const ESP_Mail_X509List *client_CA_ta);
// RSA keyed server
bool _connectSSLServerRSA(const ESP_Mail_X509List *chain, const PrivateKey *sk, const ESP_Mail_X509List *client_CA_ta);
// EC keyed server
bool _connectSSLServerEC(const ESP_Mail_X509List *chain, unsigned cert_issuer_key_type, const PrivateKey *sk,
const ESP_Mail_X509List *client_CA_ta);
// X.509 validators differ from server to client
bool _installClientX509Validator(); // Set up X509 validator for a client conn.
bool _installServerX509Validator(const ESP_Mail_X509List *client_CA_ta); // Setup X509 client cert validation, if supplied
uint8_t *_streamLoad(Stream& stream, size_t size);
};
};
#endif /* ESP8266 */
#endif /* ESP_Mail_WCS_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,278 +0,0 @@
/*
* Created by K. Suwatchai (Mobizt)
*
* Email: k_suwatchai@hotmail.com
*
* Github: https://github.com/mobizt
*
* Copyright (c) 2019 mobizt
*
*/
//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
//To receive Email for Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
/*
===========================================================================================================================
To prevent stack overrun in case of you want to download email attachments in IMAP readMail,
increase the stack size in app_main() in esp32 main.cpp will help by change the stack size from 8192 to any more value
as following
xTaskCreatePinnedToCore(loopTask, "loopTask", 8192, NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE);
to
xTaskCreatePinnedToCore(loopTask, "loopTask", 16384, NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE);
For Arduino, file esp32's main.cpp is at C:\Users\USER_NAME\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.1\cores\esp32\main.cpp
And for platformIO, that file is at C:\Users\USER_NAME\.platformio\packages\framework-arduinoespressif32\cores\esp32\main.cpp
===========================================================================================================================
*/
#include <Arduino.h>
#include "ESP32_MailClient.h"
#include "SD.h"
#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
//The Email Reading data object contains config and data that received
IMAPData imapData;
//Callback function to get the Email reading status
void readCallback(ReadStatus info);
//List all files in SD card
void printDirectory(File &dir, int depth);
void readEmail();
unsigned long lastTime = 0;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
MailClient.sdBegin();
//MailClient.sdBegin(14,2,15,13); //SCK, MISO, MOSI,SS for TTGO T8 v1.7 or 1.8
File dir = SD.open("/");
printDirectory(dir, 0);
Serial.println();
imapData.setLogin("imap.gmail.com", 993, "YOUR_EMAIL_ACCOUNT@gmail.com", "YOUR_EMAIL_PASSWORD");
imapData.setFolder("INBOX");
//Clear fetch UID
//If fetch UID was set, no search is perform.
imapData.setFetchUID("");
//imapData.setSearchCriteria("UID SINCE 10-Feb-2019");
//imapData.setSearchCriteria("UID 700:*");
//imapData.setSearchCriteria("UID SEARCH NOT SEEN");
//imapData.setSearchCriteria("UID SEARCH UNSEEN");
imapData.setSearchCriteria("UID SEARCH ALL");
//To fetch or read one message UID = 320
//imapData.setFechUID("320");
//Set SD folder to save download messages and attachments
imapData.setSaveFilePath("/email_data");
//Save attachament
imapData.setDownloadAttachment(true);
//Set fetch/search result to return html message
imapData.setHTMLMessage(true);
//Set fetch/search result to return text message
imapData.setTextMessage(true);
//Set to save html message in SD card with decoded content.
imapData.saveHTMLMessage(true, true);
//Set to save text message in SD card with decoded content.
imapData.saveTextMessage(true, true);
//Set the maximum result when search criteria was set.
imapData.setSearchLimit(10);
//Set the sort order of returning message upon most recent received email.
imapData.setRecentSort(true);
//Set the return tex/html message size in byte.
imapData.setMessageBufferSize(200);
//Set the maximum attachment size 5 MB (each file)
imapData.setAttachmentSizeLimit(1024 * 1024 * 5);
//Set the Email receive callback function.
imapData.setReadCallback(readCallback);
//Set to get attachment downloading progress status.
imapData.setDownloadReport(true);
//Set the storage types to save download attachments or messages (SD is default)
//imapData.setFileStorageType(MailClientStorageType::SPIFFS)
imapData.setFileStorageType(MailClientStorageType::SD);
MailClient.readMail(imapData);
}
void readEmail()
{
Serial.println();
Serial.println("Read Email...");
imapData.setFetchUID("10");
imapData.setSearchCriteria("");
MailClient.readMail(imapData);
imapData.setFetchUID("11");
imapData.setSearchCriteria("");
MailClient.readMail(imapData);
imapData.setFetchUID("12");
imapData.setSearchCriteria("");
MailClient.readMail(imapData);
}
void loop()
{
if (millis() - lastTime > 1000 * 60 * 3)
{
lastTime = millis();
Serial.println(ESP.getFreeHeap());
readEmail();
}
}
//Callback function to get the Email reading status
void readCallback(ReadStatus msg)
{
//Print the current status
Serial.println("INFO: " + msg.info());
if (msg.status() != "")
Serial.println("STATUS: " + msg.status());
//Show the result when reading finished
if (msg.success())
{
for (int i = 0; i < imapData.availableMessages(); i++)
{
Serial.println("=================");
//Search result number which varied upon search crieria
Serial.println("Messsage Number: " + imapData.getNumber(i));
//UID only available when assigned UID keyword in setSearchCriteria
//e.g. imapData.setSearchCriteria("UID SEARCH ALL");
Serial.println("Messsage UID: " + imapData.getUID(i));
Serial.println("Messsage ID: " + imapData.getMessageID(i));
Serial.println("Accept Language: " + imapData.getAcceptLanguage(i));
Serial.println("Content Language: " + imapData.getContentLanguage(i));
Serial.println("From: " + imapData.getFrom(i));
Serial.println("From Charset: " + imapData.getFromCharset(i));
Serial.println("To: " + imapData.getTo(i));
Serial.println("To Charset: " + imapData.getToCharset(i));
Serial.println("CC: " + imapData.getCC(i));
Serial.println("CC Charset: " + imapData.getCCCharset(i));
Serial.println("Date: " + imapData.getDate(i));
Serial.println("Subject: " + imapData.getSubject(i));
Serial.println("Subject Charset: " + imapData.getSubjectCharset(i));
//If setHeaderOnly to false;
if (!imapData.isHeaderOnly())
{
Serial.println("Text Message: " + imapData.getTextMessage(i));
Serial.println("Text Message Charset: " + imapData.getTextMessgaeCharset(i));
Serial.println("HTML Message: " + imapData.getHTMLMessage(i));
Serial.println("HTML Message Charset: " + imapData.getHTMLMessgaeCharset(i));
if (imapData.isFetchMessageFailed(i))
Serial.println("Fetch Error: " + imapData.getFetchMessageFailedReason(i));
if (imapData.isDownloadMessageFailed(i))
Serial.println("Save Content Error: " + imapData.getDownloadMessageFailedReason(i));
if (imapData.getAttachmentCount(i) > 0)
{
Serial.println("**************");
Serial.println("Attachment: " + String(imapData.getAttachmentCount(i)) + " file(s)");
for (int j = 0; j < imapData.getAttachmentCount(i); j++)
{
Serial.println("File Index: " + String(j + 1));
Serial.println("Filename: " + imapData.getAttachmentFileName(i, j));
Serial.println("Name: " + imapData.getAttachmentName(i, j));
Serial.println("Size: " + String(imapData.getAttachmentFileSize(i, j)));
Serial.println("Type: " + imapData.getAttachmentType(i, j));
Serial.println("Creation Date: " + imapData.getAttachmentCreationDate(i, j));
if (imapData.isDownloadAttachmentFailed(i, j))
Serial.println("Download Attachment Error: " + imapData.getDownloadAttachmentFailedReason(i, j));
}
}
}
Serial.println();
}
}
}
//List all files in SD card
void printDirectory(File &dir, int depth)
{
while (true)
{
File entry = dir.openNextFile();
if (!entry)
break;
for (uint8_t i = 0; i < depth; i++)
Serial.print("| ");
std::string name = entry.name();
if (entry.isDirectory())
{
Serial.print("+----" + String(name.substr(name.find_last_of("/\\") + 1).c_str()) + "\r\n");
printDirectory(entry, depth + 1);
}
else
{
Serial.print("+--" + String(name.substr(name.find_last_of("/\\") + 1).c_str()));
Serial.print("\t\t\t(");
Serial.print(entry.size(), DEC);
Serial.println(")");
}
entry.close();
}
}

View File

@ -1,180 +0,0 @@
/*
* Created by K. Suwatchai (Mobizt)
*
* Email: k_suwatchai@hotmail.com
*
* Github: https://github.com/mobizt
*
* Copyright (c) 2019 mobizt
*
*/
//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
//To receive Email for Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
#include <Arduino.h>
#include "ESP32_MailClient.h"
#include "SD.h"
//For demo only
#include "image.h"
#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
//The Email Sending data object contains config and data to send
SMTPData smtpData;
//Callback function to get the Email sending status
void sendCallback(SendStatus info);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
Serial.println("Mounting SD Card...");
if (SD.begin()) // MailClient.sdBegin(14,2,15,13) for TTGO T8 v1.7 or 1.8
{
Serial.println("Preparing attach file...");
File file = SD.open("/text_file.txt", FILE_WRITE);
file.print("Hello World!\r\nHello World!");
file.close();
file = SD.open("/binary_file.dat", FILE_WRITE);
static uint8_t buf[512];
buf[0] = 'H';
buf[1] = 'E';
buf[2] = 'A';
buf[3] = 'D';
file.write(buf, 4);
size_t i;
memset(buf, 0xff, 512);
for (i = 0; i < 2048; i++)
{
file.write(buf, 512);
}
buf[0] = 'T';
buf[1] = 'A';
buf[2] = 'I';
buf[3] = 'L';
file.write(buf, 4);
file.close();
}
else
{
Serial.println("SD Card Monting Failed");
}
Serial.println();
Serial.println("Sending email...");
//Set the Email host, port, account and password
smtpData.setLogin("outlook.office365.com", 587, "YOUR_EMAIL_ACCOUNT@outlook.com", "YOUR_EMAIL_PASSWORD");
//For library version 1.2.0 and later which STARTTLS protocol was supported,the STARTTLS will be
//enabled automatically when port 587 was used, or enable it manually using setSTARTTLS function.
//smtpData.setSTARTTLS(true);
//Set the sender name and Email
smtpData.setSender("ESP32", "SOME_EMAIL_ACCOUNT@SOME_EMAIL.com");
//Set Email priority or importance High, Normal, Low or 1 to 5 (1 is highest)
smtpData.setPriority("High");
//Set the subject
smtpData.setSubject("ESP32 SMTP Mail Sending Test");
//Set the message - normal text or html format
smtpData.setMessage("<div style=\"color:#ff0000;font-size:20px;\">Hello World! - From ESP32</div>", true);
//Add recipients, can add more than one recipient
smtpData.addRecipient("SOME_RECIPIENT@SOME_MAIL.com");
//Add attachments, can add the file or binary data from flash memory, file in SD card
//Data from internal memory
smtpData.addAttachData("firebase_logo.png", "image/png", (uint8_t *)dummyImageData, sizeof dummyImageData);
//Add attach files from SD card
//Comment these two lines, if no SD card connected
//Two files that previousely created.
smtpData.addAttachFile("/binary_file.dat");
smtpData.addAttachFile("/text_file.txt");
//Add some custom header to message
//See https://tools.ietf.org/html/rfc822
//These header fields can be read from raw or source of message when it received)
smtpData.addCustomMessageHeader("Date: Sat, 10 Aug 2019 21:39:56 -0700 (PDT)");
//Be careful when set Message-ID, it should be unique, otherwise message will not store
//smtpData.addCustomMessageHeader("Message-ID: <abcde.fghij@gmail.com>");
//Set the storage types to read the attach files (SD is default)
//smtpData.setFileStorageType(MailClientStorageType::SPIFFS);
smtpData.setFileStorageType(MailClientStorageType::SD);
smtpData.setSendCallback(sendCallback);
//Start sending Email, can be set callback function to track the status
if (!MailClient.sendMail(smtpData))
Serial.println("Error sending Email, " + MailClient.smtpErrorReason());
//Clear all data from Email object to free memory
smtpData.empty();
}
void loop()
{
}
//Callback function to get the Email sending status
void sendCallback(SendStatus msg)
{
//Print the current status
Serial.println(msg.info());
//Do something when complete
if (msg.success())
{
Serial.println("----------------");
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,70 +0,0 @@
/*
* Created by K. Suwatchai (Mobizt)
*
* Email: k_suwatchai@hotmail.com
*
* Github: https://github.com/mobizt
*
* Copyright (c) 2019 mobizt
*
*/
#include <Arduino.h>
#include "ESP32_MailClient.h"
#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
//The Email Reading data object contains config and data that received
IMAPData imapData;
void readEmail();
unsigned long lastTime = 0;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
Serial.println();
imapData.setLogin("imap.gmail.com", 993, "YOUR_EMAIL_ACCOUNT@gmail.com", "YOUR_EMAIL_PASSWORD");
imapData.setFolder("INBOX");
imapData.setDebug(true);
//Set \Seen and \Answered to flags for message with UID 100
MailClient.setFlag(imapData, 100, "\\Seen \\Answered");
//Add \Seen and \Answered to flags for message with UID 100
//MailClient.addFlag(imapData, 100, "\\Seen \\Answered");
//Remove \Seen and \Answered from flags for message with UID 100
//MailClient.removeFlag(imapData, 100, "\\Seen \\Answered");
}
void loop()
{
}

View File

@ -1,136 +0,0 @@
/*
* Created by K. Suwatchai (Mobizt)
*
* Email: k_suwatchai@hotmail.com
*
* Github: https://github.com/mobizt
*
* Copyright (c) 2019 mobizt
*
*/
#include <Arduino.h>
#include "ESP32_MailClient.h"
#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to AP");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(200);
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println();
//Set Clock
//GMT offset (3 Hrs), Daylight offset (0 Hrs)
MailClient.Time.setClock(3, 0);
Serial.println("Number of Days This Year (since January): " + String(MailClient.Time.getNumberOfDayThisYear()));
Serial.println("Day of Week Number: " + String(MailClient.Time.getDayOfWeek()));
Serial.println("Day of Week String: : " + String(MailClient.Time.getDayOfWeekString()));
Serial.println("Total seconds today: : " + String(MailClient.Time.getCurrentSecond()));
Serial.println();
}
void loop()
{
if (!MailClient.Time.clockReady)
return;
//Print out current date and time
int d = MailClient.Time.getDay();
int m = MailClient.Time.getMonth();
int y = MailClient.Time.getYear();
int hr = MailClient.Time.getHour();
int min = MailClient.Time.getMin();
int sec = MailClient.Time.getSec();
Serial.print("Current Time (GMT+3): ");
Serial.print(d);
Serial.print("/");
Serial.print(m);
Serial.print("/");
Serial.print(y);
Serial.print(" ");
Serial.print(hr);
Serial.print(":");
Serial.print(min);
Serial.print(":");
Serial.println(sec);
uint32_t todayFromMidnightTimestamp = MailClient.Time.getTimestamp(y, m, d, 0, 0, 0);
uint32_t currentTimestamp = MailClient.Time.getUnixTime();
uint32_t totalSecondsFromMidnight = currentTimestamp - todayFromMidnightTimestamp;
//Assumed we countdown until 15:00:00 everyday
uint8_t targetSec = 0;
uint8_t targetMin = 0;
uint8_t targetHr = 15;
uint32_t targetSecondsFromMidnight = targetHr * 60 * 60 + targetMin * 60 + targetSec;
if (targetSecondsFromMidnight >= totalSecondsFromMidnight)
{
uint32_t diffSeconds = targetSecondsFromMidnight - totalSecondsFromMidnight;
int remainYrs, remainMonths, remainDays, remainHr, remainMin, remainSec;
MailClient.Time.getTimeFromSec(diffSeconds, remainYrs, remainMonths, remainDays, remainHr, remainMin, remainSec);
Serial.print("Everyday countdown until 15:00:00 is ");
Serial.print(remainHr);
Serial.print(" Hr, ");
Serial.print(remainMin);
Serial.print(" Min and ");
Serial.print(remainSec);
Serial.println(" Sec to go.");
}
else
{
Serial.println("Everyday countdown until 15:00:00 was passed.");
}
//Assumed we countdown until 18/12/2019 8:30:45
uint32_t targetTimestamp = MailClient.Time.getTimestamp(2019, 12, 18, 8, 30, 45);
if (targetTimestamp >= currentTimestamp)
{
uint32_t diffSeconds = targetTimestamp - currentTimestamp;
int remainYrs, remainMonths, remainDays, remainHr, remainMin, remainSec;
MailClient.Time.getTimeFromSec(diffSeconds, remainYrs, remainMonths, remainDays, remainHr, remainMin, remainSec);
Serial.print("One time countdown until 18/12/2019 8:30:45 is ");
Serial.print(remainYrs);
Serial.print(" Years, ");
Serial.print(remainMonths);
Serial.print(" Months, ");
Serial.print(remainDays);
Serial.print(" Days, ");
Serial.print(remainHr);
Serial.print(" Hr, ");
Serial.print(remainMin);
Serial.print(" Min and ");
Serial.print(remainSec);
Serial.println(" Sec to go.");
}
else
{
Serial.println("One time countdown until 18/12/2019 8:30:45 was finished.");
}
Serial.println();
delay(1000);
}

View File

@ -1,166 +0,0 @@
#######################################
# Syntax Coloring Map ESP32-Mail-Client
#######################################
#######################################
# Classes (KEYWORD1)
#######################################
IMAPData KEYWORD1
SMTPData KEYWORD1
attachmentData KEYWORD1
SendStatus KEYWORD1
messageBodyData KEYWORD1
DownloadProgress KEYWORD1
MessageData KEYWORD1
TIME KEYWORD1
##################################
# Methods and Functions (KEYWORD2)
##################################
sendMail KEYWORD2
readMail KEYWORD2
smtpErrorReason KEYWORD2
imapErrorReason KEYWORD2
sdBegin KEYWORD2
setFlag KEYWORD2
addFlag KEYWORD2
removeFlag KEYWORD2
setClock KEYWORD2
getUnixTime KEYWORD2
getTimestamp KEYWORD2
getYear KEYWORD2
getMonth KEYWORD2
getDay KEYWORD2
getDayOfWeek KEYWORD2
getDayOfWeekString KEYWORD2
getHour KEYWORD2
getMin KEYWORD2
getSec KEYWORD2
getNumberOfDayThisYear KEYWORD2
getTotalDays KEYWORD2
dayofweek KEYWORD2
getCurrentSecond KEYWORD2
getCurrentTimestamp KEYWORD2
getTimeFromSec KEYWORD2
#########################################
# Methods for IMAP Data object (KEYWORD2)
#########################################
setLogin KEYWORD2
setSTARTTLS KEYWORD2
setDebug KEYWORD2
setFolder KEYWORD2
setMessageBufferSize KEYWORD2
setAttachmentSizeLimit KEYWORD2
setSearchCriteria KEYWORD2
setSaveFilePath KEYWORD2
setFechUID KEYWORD2
setDownloadAttachment KEYWORD2
setHTMLMessage KEYWORD2
setTextMessage KEYWORD2
setSearchLimit KEYWORD2
setRecentSort KEYWORD2
setReadCallback KEYWORD2
setDownloadReport KEYWORD2
isHeaderOnly KEYWORD2
getFrom KEYWORD2
getFromCharset KEYWORD2
getTo KEYWORD2
getToCharset KEYWORD2
getCC KEYWORD2
getCCCharset KEYWORD2
getSubject KEYWORD2
getSubjectCharset KEYWORD2
getHTMLMessage KEYWORD2
getTextMessage KEYWORD2
getHTMLMessgaeCharset KEYWORD2
getTextMessgaeCharset KEYWORD2
getDate KEYWORD2
getUID KEYWORD2
getNumber KEYWORD2
getMessageID KEYWORD2
getAcceptLanguage KEYWORD2
getContentLanguage KEYWORD2
isFetchMessageFailed KEYWORD2
getFetchMessageFailedReason KEYWORD2
isDownloadAttachmentFailed KEYWORD2
getDownloadAttachmentFailedReason KEYWORD2
isDownloadMessageFailed KEYWORD2
getDownloadMessageFailedReason KEYWORD2
saveHTMLMessage KEYWORD2
saveTextMessage KEYWORD2
getFolderCount KEYWORD2
getFolder KEYWORD2
getFlagCount KEYWORD2
getFlag KEYWORD2
totalMessages KEYWORD2
searchCount KEYWORD2
availableMessages KEYWORD2
getAttachmentCount KEYWORD2
getAttachmentFileName KEYWORD2
getAttachmentName KEYWORD2
getAttachmentFileSize KEYWORD2
getAttachmentCreationDate KEYWORD2
getAttachmentType KEYWORD2
empty KEYWORD2
clearMessageData KEYWORD2
#########################################
# Methods for SMTP Data object (KEYWORD2)
#########################################
setSender KEYWORD2
getFromName KEYWORD2
getSenderEmail KEYWORD2
setPriority KEYWORD2
getPriority KEYWORD2
addRecipient KEYWORD2
removeRecipient KEYWORD2
clearRecipient KEYWORD2
getRecipient KEYWORD2
recipientCount KEYWORD2
setSubject KEYWORD2
getSubject KEYWORD2
setMessage KEYWORD2
getMessage KEYWORD2
htmlFormat KEYWORD2
addCC KEYWORD2
removeCC KEYWORD2
clearCC KEYWORD2
getCC KEYWORD2
ccCount KEYWORD2
addBCC KEYWORD2
removeBCC KEYWORD2
clearBCC KEYWORD2
getBCC KEYWORD2
bccCount KEYWORD2
addAttachData KEYWORD2
removeAttachData KEYWORD2
attachDataCount KEYWORD2
addAttachFile KEYWORD2
removeAttachFile KEYWORD2
clearAttachData KEYWORD2
clearAttachFile KEYWORD2
clearAttachment KEYWORD2
attachFileCount KEYWORD2
setSendCallback KEYWORD2
############################################################
# Functions for ReadStatus and SendStatus classes (KEYWORD2)
############################################################
SendStatus KEYWORD2
info KEYWORD2
success KEYWORD2
ReadStatus KEYWORD2
status KEYWORD2
clockReady KEYWORD3

View File

@ -1,8 +0,0 @@
{
"name": "ESP32 Mail Client",
"keywords": "esp32, mail, communication",
"description": "Mail Client Arduino Library for ESP32",
"version": "2.1.4",
"frameworks": "arduino",
"platforms": "espressif32"
}

View File

@ -1,9 +0,0 @@
name=ESP32 Mail Client
version=2.1.4
author=Mobizt
maintainer=Mobizt <k_suwatchai@hotmail.com.com>
sentence=Mail Client Arduino Library for ESP32
paragraph=This library allows ESP32 to send Email with/without attachment and receive Email with/without attachment download through SMTP and IMAP servers.
category=Communication
url=https://github.com/mobizt/ESP32-Mail-Client
architectures=esp32

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,200 +0,0 @@
/*
* Customized version of ESP32 HTTPClient Library.
* Allow custom header and payload with STARTTLS support
*
* v 1.0.0
*
* The MIT License (MIT)
* Copyright (c) 2019 K. Suwatchai (Mobizt)
*
* HTTPClient Arduino library for ESP32
*
* Copyright (c) 2015 Markus Sattler. All rights reserved.
* This file is part of the HTTPClient for Arduino.
* Port to ESP32 by Evandro Luis Copercini (2017),
* changed fingerprints to CA verification.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef ESP32MailHTTPClient_CPP
#define ESP32MailHTTPClient_CPP
#ifdef ESP32
#include "ESP32MailHTTPClient.h"
class TransportTraits
{
public:
virtual ~TransportTraits() {}
virtual std::unique_ptr<WiFiClient> create()
{
return std::unique_ptr<WiFiClient>(new WiFiClient());
}
virtual bool
verify(WiFiClient &client, const char *host, bool starttls, DebugMsgCallback cb)
{
return true;
}
};
class TLSTraits : public TransportTraits
{
public:
TLSTraits(const char *CAcert, const char *clicert = nullptr, const char *clikey = nullptr) : _cacert(CAcert), _clicert(clicert), _clikey(clikey) {}
std::unique_ptr<WiFiClient> create() override
{
return std::unique_ptr<WiFiClient>(new WiFiClientSecureESP32());
}
bool verify(WiFiClient &client, const char *host, bool starttls, DebugMsgCallback cb) override
{
WiFiClientSecureESP32 &wcs = static_cast<WiFiClientSecureESP32 &>(client);
wcs.setCACert(_cacert);
wcs.setCertificate(_clicert);
wcs.setPrivateKey(_clikey);
wcs.setSTARTTLS(starttls);
wcs.setDebugCB(cb);
return true;
}
protected:
const char *_cacert;
const char *_clicert;
const char *_clikey;
};
ESP32MailHTTPClient::ESP32MailHTTPClient() {}
ESP32MailHTTPClient::~ESP32MailHTTPClient()
{
if (_client)
_client->stop();
}
bool ESP32MailHTTPClient::begin(const char *host, uint16_t port, const char *uri, const char *CAcert)
{
transportTraits.reset(nullptr);
_host = host;
_port = port;
_uri = uri;
transportTraits = TransportTraitsPtr(new TLSTraits(CAcert));
return true;
}
bool ESP32MailHTTPClient::connected()
{
if (_client)
return ((_client->available() > 0) || _client->connected());
return false;
}
bool ESP32MailHTTPClient::sendHeader(const char *header)
{
if (!connected())
return false;
return (_client->write(header, strlen(header)) == strlen(header));
}
int ESP32MailHTTPClient::sendRequest(const char *header, const char *payload)
{
size_t size = strlen(payload);
if (strlen(header) > 0)
{
if (!connect())
return HTTPC_ERROR_CONNECTION_REFUSED;
if (!sendHeader(header))
return HTTPC_ERROR_SEND_HEADER_FAILED;
}
if (size > 0)
if (_client->write(&payload[0], size) != size)
return HTTPC_ERROR_SEND_PAYLOAD_FAILED;
return 0;
}
WiFiClient *ESP32MailHTTPClient::getStreamPtr(void)
{
if (connected())
return _client.get();
return nullptr;
}
bool ESP32MailHTTPClient::connect(void)
{
if (connected())
{
while (_client->available() > 0)
_client->read();
return true;
}
if (!transportTraits)
return false;
_client = transportTraits->create();
if (!transportTraits->verify(*_client, _host.c_str(), false, _debugCallback))
{
_client->stop();
return false;
}
if (!_client->connect(_host.c_str(), _port))
return false;
return connected();
}
bool ESP32MailHTTPClient::connect(bool starttls)
{
if (connected())
{
while (_client->available() > 0)
_client->read();
return true;
}
if (!transportTraits)
return false;
_client = transportTraits->create();
if (!transportTraits->verify(*_client, _host.c_str(), starttls, _debugCallback))
{
_client->stop();
return false;
}
if (!_client->connect(_host.c_str(), _port))
return false;
return connected();
}
void ESP32MailHTTPClient::setDebugCallback(DebugMsgCallback cb)
{
_debugCallback = std::move(cb);
}
#endif //ESP32
#endif //ESP32MailHTTPClient_CPP

View File

@ -1,107 +0,0 @@
/*
* Customized version of ESP32 HTTPClient Library.
* Allow custom header and payload with STARTTLS support
*
* v 1.0.0
*
* The MIT License (MIT)
* Copyright (c) 2019 K. Suwatchai (Mobizt)
*
* HTTPClient Arduino library for ESP32
*
* Copyright (c) 2015 Markus Sattler. All rights reserved.
* This file is part of the HTTPClient for Arduino.
* Port to ESP32 by Evandro Luis Copercini (2017),
* changed fingerprints to CA verification.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef ESP32MailHTTPClient_H
#define ESP32MailHTTPClient_H
#ifdef ESP32
#include <Arduino.h>
#include <HTTPClient.h>
#include <WiFiClient.h>
#include "WiFiClientSecureESP32.h"
class ESP32MailHTTPClient : public HTTPClient
{
public:
ESP32MailHTTPClient();
~ESP32MailHTTPClient();
/**
* Initialization of new http connection.
* \param host - Host name without protocols.
* \param port - Server's port.
* \param uri - The URI of resource.
* \param CAcert - The Base64 encode root certificate string
* \return True as default.
* If no certificate string provided, use (const char*)NULL to CAcert param
*/
bool begin(const char *host, uint16_t port, const char *uri, const char *CAcert);
/**
* Check the http connection status.
* \return True if connected.
*/
bool connected();
/**
* Establish http connection if header provided and send it, send payload if provided.
* \param header - The header string (constant chars array).
* \param payload - The payload string (constant chars array), optional.
* \return http status code, Return zero if new http connection and header and/or payload sent
* with no error or no header and payload provided. If obly payload provided, no new http connection was established.
*/
int sendRequest(const char *header, const char *payload);
/**
* Send extra header without making new http connection (if sendRequest has been called)
* \param header - The header string (constant chars array).
* \return True if header sending success.
* Need to call sendRequest with header first.
*/
bool sendHeader(const char *header);
/**
* Get the WiFi client pointer.
* \return WiFi client pointer.
*/
WiFiClient *getStreamPtr(void);
uint16_t tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
bool connect(void);
bool connect(bool starttls);
void setDebugCallback(DebugMsgCallback cb);
protected:
TransportTraitsPtr transportTraits;
std::unique_ptr<WiFiClient> _client;
DebugMsgCallback _debugCallback = NULL;
std::string _host = "";
std::string _uri = "";
uint16_t _port = 0;
};
#endif //ESP32
#endif //ESP32MailHTTPClient_H

View File

@ -1,191 +0,0 @@
/*
* ESP32 Internet Time Helper Arduino Library v 1.0.1
*
* The MIT License (MIT)
* Copyright (c) 2019 K. Suwatchai (Mobizt)
*
*
* Permission is hereby granted, free of charge, to any person returning 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.
*/
#ifndef ESP32TimeHelper_CPP
#define ESP32TimeHelper_CPP
#ifdef ESP32
#include "ESP32TimeHelper.h"
ESP32TimeHelper::ESP32TimeHelper()
{
}
uint32_t ESP32TimeHelper::getUnixTime()
{
uint32_t utime = (msec_time_diff + millis()) / 1000;
return utime;
}
time_t ESP32TimeHelper::getTimestamp(int year, int mon, int date, int hour, int mins, int sec)
{
struct tm timeinfo;
timeinfo.tm_year = year - 1900;
timeinfo.tm_mon = mon - 1;
timeinfo.tm_mday = date;
timeinfo.tm_hour = hour;
timeinfo.tm_min = mins;
timeinfo.tm_sec = sec;
time_t ts = mktime(&timeinfo);
return ts;
}
bool ESP32TimeHelper::setClock(float gmtOffset, float daylightOffset)
{
TZ = gmtOffset;
DST_MN = daylightOffset;
configTime((TZ)*3600, (DST_MN)*60, "pool.ntp.org", "time.nist.gov", NULL);
now = time(nullptr);
int cnt = 0;
while (now < 8 * 3600 * 2 && cnt < 20)
{
delay(50);
now = time(nullptr);
cnt++;
}
uint64_t tmp = now;
tmp = tmp * 1000;
msec_time_diff = tmp - millis();
getLocalTime(&timeinfo);
clockReady = now > 8 * 3600 * 2;
return clockReady;
}
int ESP32TimeHelper::getYear()
{
getLocalTime(&timeinfo);
return timeinfo.tm_year + 1900;
}
int ESP32TimeHelper::getMonth()
{
getLocalTime(&timeinfo);
return timeinfo.tm_mon + 1;
}
int ESP32TimeHelper::getDay()
{
getLocalTime(&timeinfo);
return timeinfo.tm_mday;
}
int ESP32TimeHelper::getDayOfWeek()
{
getLocalTime(&timeinfo);
return timeinfo.tm_wday;
}
String ESP32TimeHelper::getDayOfWeekString()
{
getLocalTime(&timeinfo);
return dow[timeinfo.tm_wday];
}
int ESP32TimeHelper::getHour()
{
getLocalTime(&timeinfo);
return timeinfo.tm_hour;
}
int ESP32TimeHelper::getMin()
{
getLocalTime(&timeinfo);
return timeinfo.tm_min;
}
int ESP32TimeHelper::getSec()
{
getLocalTime(&timeinfo);
return timeinfo.tm_sec;
}
int ESP32TimeHelper::getNumberOfDayThisYear()
{
getLocalTime(&timeinfo);
return timeinfo.tm_yday + 1;
}
int ESP32TimeHelper::totalDays(int y, int m, int d)
{
static char daytab[2][13] =
{
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
int daystotal = d;
for (int year = 1; year <= y; year++)
{
int max_month = (year < y ? 12 : m - 1);
int leap = (year % 4 == 0);
if (year % 100 == 0 && year % 400 != 0)
leap = 0;
for (int month = 1; month <= max_month; month++)
{
daystotal += daytab[leap][month];
}
}
return daystotal;
}
int ESP32TimeHelper::getTotalDays(int year, int month, int day)
{
return totalDays(year, month, day) - totalDays(1970, 1, 1);
}
int ESP32TimeHelper::dayofWeek(int year, int month, int day) /* 1 <= m <= 12, y > 1752 (in the U.K.) */
{
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
year -= month < 3;
return (year + year / 4 - year / 100 + year / 400 + t[month - 1] + day) % 7;
}
int ESP32TimeHelper::getCurrentSecond()
{
return (timeinfo.tm_hour * 3600) + (timeinfo.tm_min * 60) + timeinfo.tm_sec;
}
uint64_t ESP32TimeHelper::getCurrentTimestamp()
{
return now;
}
void ESP32TimeHelper::getTimeFromSec(int secCount, int &yrs, int &months, int &days, int &hr, int &min, int &sec)
{
int _yrs = secCount / (365 * 24 * 3600);
secCount = secCount - _yrs * (365 * 24 * 3600);
yrs = _yrs;
int _months = secCount / (30* 24 * 3600);
secCount = secCount - _months * (30 * 24 * 3600);
months = _months;
int _days = secCount / (24 * 3600);
secCount = secCount - _days * (24 * 3600);
days = _days;
int _hr = secCount / 3600;
secCount = secCount - _hr * 3600;
hr = _hr;
int _min = secCount / 60;
secCount = secCount - _min * 60;
min = _min;
sec = secCount;
}
#endif //ESP32
#endif //ESP32TimeHelper_CPP

View File

@ -1,73 +0,0 @@
/*
* ESP32 Internet Time Helper Arduino Library v 1.0.1
*
* The MIT License (MIT)
* Copyright (c) 2019 K. Suwatchai (Mobizt)
*
*
* Permission is hereby granted, free of charge, to any person returning 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.
*/
#ifndef ESP32TimeHelper_H
#define ESP32TimeHelper_H
#ifdef ESP32
#include <time.h>
#include <Arduino.h>
#include <WiFi.h>
class ESP32TimeHelper
{
public:
ESP32TimeHelper();
bool clockReady = false;
bool setClock(float gmtOffset, float daylightOffset);
uint32_t getUnixTime();
time_t getTimestamp(int year, int mon, int date, int hour, int mins, int sec);
int getYear();
int getMonth();
int getDay();
int getDayOfWeek();
String getDayOfWeekString();
int getHour();
int getMin();
int getSec();
int getNumberOfDayThisYear();
int getTotalDays(int year, int month, int day);
int dayofWeek(int year, int month, int day);
int getCurrentSecond();
uint64_t getCurrentTimestamp();
void getTimeFromSec(int secCount, int &yrs, int &months, int &days, int &hr, int &min, int &sec);
private:
time_t now;
uint64_t msec_time_diff = 0;
struct tm timeinfo;
float TZ = 0.0;
float DST_MN = 0.0;
bool setClock();
int totalDays(int y, int m, int d);
const char *dow[20] = {"sunday", "monday", "tuesday", "wednesday", "thurseday", "friday", "saturday"};
};
#endif //ESP32
#endif //ESP32TimeHelper_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,397 +0,0 @@
/*
*Customized WiFiClientSecure.cpp to support STARTTLS protocol, version 1.0.1
*
* The MIT License (MIT)
* Copyright (c) 2019 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.
*/
/*
WiFiClientSecureESP32.cpp - Client Secure class for ESP32
Copyright (c) 2016 Hristo Gochkov All right reserved.
Additions Copyright (C) 2017 Evandro Luis Copercini.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef WiFiClientSecureESP32_CPP
#define WiFiClientSecureESP32_CPP
#ifdef ESP32
#include "WiFiClientSecureESP32.h"
#include <lwip/sockets.h>
#include <lwip/netdb.h>
#include <errno.h>
#undef connect
#undef write
#undef read
WiFiClientSecureESP32::WiFiClientSecureESP32()
{
_connected = false;
sslclient = new sslclient_context32;
ssl_init(sslclient);
sslclient->socket = -1;
sslclient->handshake_timeout = 120000;
_CA_cert = NULL;
_cert = NULL;
_private_key = NULL;
_pskIdent = NULL;
_psKey = NULL;
next = NULL;
}
WiFiClientSecureESP32::WiFiClientSecureESP32(int sock)
{
_connected = false;
_timeout = 0;
sslclient = new sslclient_context32;
ssl_init(sslclient);
sslclient->socket = sock;
sslclient->handshake_timeout = 120000;
if (sock >= 0) {
_connected = true;
}
_CA_cert = NULL;
_cert = NULL;
_private_key = NULL;
_pskIdent = NULL;
_psKey = NULL;
next = NULL;
}
WiFiClientSecureESP32::WiFiClientSecureESP32(bool starttls)
{
_connected = false;
sslclient = new sslclient_context32;
ssl_init(sslclient);
sslclient->socket = -1;
sslclient->handshake_timeout = 120000;
sslclient->starttls = true;
_CA_cert = NULL;
_cert = NULL;
_private_key = NULL;
_pskIdent = NULL;
_psKey = NULL;
next = NULL;
}
WiFiClientSecureESP32::~WiFiClientSecureESP32()
{
stop();
delete sslclient;
}
WiFiClientSecureESP32 &WiFiClientSecureESP32::operator=(const WiFiClientSecureESP32 &other)
{
stop();
sslclient->socket = other.sslclient->socket;
_connected = other._connected;
return *this;
}
void WiFiClientSecureESP32::stop()
{
if (sslclient->socket >= 0) {
close(sslclient->socket);
sslclient->socket = -1;
_connected = false;
_peek = -1;
}
stop_ssl_socket(sslclient, _CA_cert, _cert, _private_key);
}
int WiFiClientSecureESP32::connect(IPAddress ip, uint16_t port)
{
if (_pskIdent && _psKey)
return connect(ip, port, _pskIdent, _psKey);
return connect(ip, port, _CA_cert, _cert, _private_key);
}
int WiFiClientSecureESP32::connect(IPAddress ip, uint16_t port, int32_t timeout){
_timeout = timeout;
return connect(ip, port);
}
int WiFiClientSecureESP32::connect(const char *host, uint16_t port)
{
if (_pskIdent && _psKey)
return connect(host, port, _pskIdent, _psKey);
return connect(host, port, _CA_cert, _cert, _private_key);
}
int WiFiClientSecureESP32::connect(const char *host, uint16_t port, int32_t timeout){
_timeout = timeout;
return connect(host, port);
}
int WiFiClientSecureESP32::connect(IPAddress ip, uint16_t port, const char *_CA_cert, const char *_cert, const char *_private_key)
{
return connect(ip.toString().c_str(), port, _CA_cert, _cert, _private_key);
}
int WiFiClientSecureESP32::connect(const char *host, uint16_t port, const char *_CA_cert, const char *_cert, const char *_private_key)
{
if(_timeout > 0){
sslclient->handshake_timeout = _timeout;
}
int ret = start_ssl_client(sslclient, host, port, _timeout, _CA_cert, _cert, _private_key, NULL, NULL);
_lastError = ret;
if (ret < 0) {
log_e("start_ssl_client: %d", ret);
stop();
return 0;
}
_connected = true;
return 1;
}
int WiFiClientSecureESP32::connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey) {
return connect(ip.toString().c_str(), port,_pskIdent, _psKey);
}
int WiFiClientSecureESP32::connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey) {
log_v("start_ssl_client with PSK");
if(_timeout > 0){
sslclient->handshake_timeout = _timeout;
}
int ret = start_ssl_client(sslclient, host, port, _timeout, NULL, NULL, NULL, _pskIdent, _psKey);
_lastError = ret;
if (ret < 0) {
log_e("start_ssl_client: %d", ret);
stop();
return 0;
}
_connected = true;
return 1;
}
int WiFiClientSecureESP32::peek(){
if(_peek >= 0){
return _peek;
}
_peek = timedRead();
return _peek;
}
size_t WiFiClientSecureESP32::write(uint8_t data)
{
return write(&data, 1);
}
int WiFiClientSecureESP32::read()
{
uint8_t data = -1;
int res = read(&data, 1);
if (res < 0) {
return res;
}
return data;
}
size_t WiFiClientSecureESP32::write(const uint8_t *buf, size_t size)
{
if (!_connected) {
return 0;
}
int res = send_ssl_data(sslclient, buf, size);
if (res < 0) {
stop();
res = 0;
}
return res;
}
int WiFiClientSecureESP32::read(uint8_t *buf, size_t size)
{
int peeked = 0;
int avail = available();
if ((!buf && size) || avail <= 0) {
return -1;
}
if(!size){
return 0;
}
if(_peek >= 0){
buf[0] = _peek;
_peek = -1;
size--;
avail--;
if(!size || !avail){
return 1;
}
buf++;
peeked = 1;
}
int res = get_ssl_receive(sslclient, buf, size);
if (res < 0) {
stop();
return peeked?peeked:res;
}
return res + peeked;
}
int WiFiClientSecureESP32::available()
{
int peeked = (_peek >= 0);
if (!_connected) {
return peeked;
}
int res = data_to_read(sslclient);
if (res < 0) {
stop();
return peeked?peeked:res;
}
return res+peeked;
}
uint8_t WiFiClientSecureESP32::connected()
{
uint8_t dummy = 0;
read(&dummy, 0);
return _connected;
}
void WiFiClientSecureESP32::setCACert (const char *rootCA)
{
_CA_cert = rootCA;
}
void WiFiClientSecureESP32::setCertificate (const char *client_ca)
{
_cert = client_ca;
}
void WiFiClientSecureESP32::setPrivateKey (const char *private_key)
{
_private_key = private_key;
}
void WiFiClientSecureESP32::setPreSharedKey(const char *pskIdent, const char *psKey) {
_pskIdent = pskIdent;
_psKey = psKey;
}
bool WiFiClientSecureESP32::verify(const char* fp, const char* domain_name)
{
if (!sslclient)
return false;
return verify_ssl_fingerprint(sslclient, fp, domain_name);
}
char *WiFiClientSecureESP32::_streamLoad(Stream& stream, size_t size) {
static char *dest = nullptr;
if(dest) {
free(dest);
}
dest = (char*)malloc(size);
if (!dest) {
return nullptr;
}
if (size != stream.readBytes(dest, size)) {
free(dest);
dest = nullptr;
}
return dest;
}
bool WiFiClientSecureESP32::loadCACert(Stream& stream, size_t size) {
char *dest = _streamLoad(stream, size);
bool ret = false;
if (dest) {
setCACert(dest);
ret = true;
}
return ret;
}
bool WiFiClientSecureESP32::loadCertificate(Stream& stream, size_t size) {
char *dest = _streamLoad(stream, size);
bool ret = false;
if (dest) {
setCertificate(dest);
ret = true;
}
return ret;
}
bool WiFiClientSecureESP32::loadPrivateKey(Stream& stream, size_t size) {
char *dest = _streamLoad(stream, size);
bool ret = false;
if (dest) {
setPrivateKey(dest);
ret = true;
}
return ret;
}
int WiFiClientSecureESP32::lastError(char *buf, const size_t size)
{
if (!_lastError) {
return 0;
}
char error_buf[100];
mbedtls_strerror(_lastError, error_buf, 100);
snprintf(buf, size, "%s", error_buf);
return _lastError;
}
void WiFiClientSecureESP32::setHandshakeTimeout(unsigned long handshake_timeout)
{
sslclient->handshake_timeout = handshake_timeout * 1000;
}
void WiFiClientSecureESP32::setSTARTTLS(bool starttls)
{
sslclient->starttls = starttls;
}
void WiFiClientSecureESP32::setDebugCB(DebugMsgCallback cb)
{
sslclient->_debugCallback = std::move(cb);
}
#endif //ESP32
#endif //WiFiClientSecureESP32_CPP

View File

@ -1,116 +0,0 @@
/*
*Customized ssl_client.h to support STARTTLS protocol, version 1.0.3
*
* The MIT License (MIT)
* Copyright (c) 2019 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.
*/
/* Provide SSL/TLS functions to ESP32 with Arduino IDE
* by Evandro Copercini - 2017 - Apache 2.0 License
*/
#ifndef SSL_CLIENT32_H
#define SSL_CLIENT32_H
#ifdef ESP32
#include "mbedtls/platform.h"
#include "mbedtls/net.h"
#include "mbedtls/debug.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
static const char ESP32_SSL_CLIENT_STR_1[] PROGMEM = "ERROR: ";
static const char ESP32_SSL_CLIENT_STR_2[] PROGMEM = "INFO: starting socket";
static const char ESP32_SSL_CLIENT_STR_3[] PROGMEM = "ERROR: opening socket";
static const char ESP32_SSL_CLIENT_STR_4[] PROGMEM = "ERROR: could not get ip from host";
static const char ESP32_SSL_CLIENT_STR_5[] PROGMEM = "INFO: connecting to Server...";
static const char ESP32_SSL_CLIENT_STR_6[] PROGMEM = "INFO: server connected";
static const char ESP32_SSL_CLIENT_STR_7[] PROGMEM = "ERROR: connect to Server failed!";
static const char ESP32_SSL_CLIENT_STR_8[] PROGMEM = "INFO: begin STARTTLS handshake";
static const char ESP32_SSL_CLIENT_STR_9[] PROGMEM = "INFO: seeding the random number generator";
static const char ESP32_SSL_CLIENT_STR_10[] PROGMEM = "INFO: setting up the SSL/TLS structure...";
static const char ESP32_SSL_CLIENT_STR_11[] PROGMEM = "INFO: loading CA cert";
static const char ESP32_SSL_CLIENT_STR_12[] PROGMEM = "INFO: setting up PSK";
static const char ESP32_SSL_CLIENT_STR_13[] PROGMEM = "ERROR: pre-shared key not valid hex or too long";
static const char ESP32_SSL_CLIENT_STR_14[] PROGMEM = "INFO: set mbedtls config";
static const char ESP32_SSL_CLIENT_STR_15[] PROGMEM = "INFO: loading CRT cert";
static const char ESP32_SSL_CLIENT_STR_16[] PROGMEM = "INFO: loading private key";
static const char ESP32_SSL_CLIENT_STR_17[] PROGMEM = "INFO: setting hostname for TLS session...";
static const char ESP32_SSL_CLIENT_STR_18[] PROGMEM = "INFO: performing the SSL/TLS handshake...";
static const char ESP32_SSL_CLIENT_STR_19[] PROGMEM = "INFO: verifying peer X.509 certificate...";
static const char ESP32_SSL_CLIENT_STR_20[] PROGMEM = "ERROR: failed to verify peer certificate!";
static const char ESP32_SSL_CLIENT_STR_21[] PROGMEM = "INFO: certificate verified";
static const char ESP32_SSL_CLIENT_STR_22[] PROGMEM = "INFO: cleaning SSL connection";
static const char ESP32_SSL_CLIENT_STR_23[] PROGMEM = "ERROR: fingerprint too short";
static const char ESP32_SSL_CLIENT_STR_24[] PROGMEM = "ERROR: invalid hex sequence";
static const char ESP32_SSL_CLIENT_STR_25[] PROGMEM = "ERROR: could not fetch peer certificate";
static const char ESP32_SSL_CLIENT_STR_26[] PROGMEM = "ERROR: fingerprint doesn't match";
static const char ESP32_SSL_CLIENT_STR_27[] PROGMEM = "ERROR: waiting incoming data failed!";
static const char ESP32_SSL_CLIENT_STR_28[] PROGMEM = "ERROR: reading incoming data failed!";
static const char ESP32_SSL_CLIENT_STR_29[] PROGMEM = "EHLO DUDE\r\n";
static const char ESP32_SSL_CLIENT_STR_30[] PROGMEM = "INFO: send SMTP command extended HELO";
static const char ESP32_SSL_CLIENT_STR_31[] PROGMEM = "ERROR: send SMTP command failed!";
static const char ESP32_SSL_CLIENT_STR_32[] PROGMEM = "ERROR: waiting incoming data failed!";
static const char ESP32_SSL_CLIENT_STR_33[] PROGMEM = "ERROR: reading incoming data failed!";
static const char ESP32_SSL_CLIENT_STR_34[] PROGMEM = "STARTTLS\r\n";
static const char ESP32_SSL_CLIENT_STR_35[] PROGMEM = "INFO: send STARTTLS protocol command";
static const char ESP32_SSL_CLIENT_STR_36[] PROGMEM = "ERROR: send STARTTLS protocol command failed!";
static const char ESP32_SSL_CLIENT_STR_37[] PROGMEM = "ERROR: waiting incoming data failed!";
static const char ESP32_SSL_CLIENT_STR_38[] PROGMEM = "ERROR: reading incoming data failed!";
typedef void (*DebugMsgCallback)(const char *msg);
typedef struct sslclient_context32 {
int socket;
bool starttls;
mbedtls_ssl_context ssl_ctx;
mbedtls_ssl_config ssl_conf;
mbedtls_net_context server_fd;
mbedtls_ctr_drbg_context drbg_ctx;
mbedtls_entropy_context entropy_ctx;
mbedtls_x509_crt ca_cert;
mbedtls_x509_crt client_cert;
mbedtls_pk_context client_key;
DebugMsgCallback _debugCallback;
unsigned long handshake_timeout;
} sslclient_context32;
void ssl_init(sslclient_context32 *ssl_client);
int start_ssl_client(sslclient_context32 *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey);
void stop_ssl_socket(sslclient_context32 *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key);
int data_to_read(sslclient_context32 *ssl_client);
int send_ssl_data(sslclient_context32 *ssl_client, const uint8_t *data, uint16_t len);
int get_ssl_receive(sslclient_context32 *ssl_client, uint8_t *data, int length);
bool verify_ssl_fingerprint(sslclient_context32 *ssl_client, const char* fp, const char* domain_name);
bool verify_ssl_dn(sslclient_context32 *ssl_client, const char* domain_name);
int starttlsHandshake(sslclient_context32 *ssl_client, int port);
void ESP32SSLClientDebugInfo(PGM_P info, sslclient_context32 *ssl_client);
#endif //ESP32
#endif //SSL_CLIENT32_H

325
tasmota/sendemail_ESP32.ino Normal file
View File

@ -0,0 +1,325 @@
#ifdef USE_ESP32MAIL
#include <ESP_Mail_Client.h>
#ifndef SEND_MAIL32_MINRAM
#define SEND_MAIL32_MINRAM 30*1024
#endif
#define xPSTR(a) a
#define MAX_ATTCHMENTS 8
char *attachments[MAX_ATTCHMENTS];
uint8_t num_attachments;
void script_send_email_body(void(*func)(char *));
String html_content = "";
SMTP_Message *email_mptr;
//#define DEBUG_EMAIL_PORT
uint16_t SendMail(char *buffer) {
char *params,*oparams = 0;
const char *mserv;
uint16_t port;
const char *user;
const char *pstr;
const char *passwd;
const char *from;
const char *to;
const char *subject;
const char *cmd;
uint16_t status = 0;
uint16_t blen;
char *endcmd;
SMTPSession smtp;
ESP_Mail_Session session;
SMTP_Message message;
email_mptr = &message;
// return if not enough memory
uint32_t mem = ESP.getFreeHeap();
//AddLog(LOG_LEVEL_INFO, PSTR("heap: %d"),mem);
if (mem < SEND_MAIL32_MINRAM) {
// return 4;
}
while (*buffer==' ') buffer++;
if (*buffer != '[') {
goto exit;
}
buffer++;
endcmd = strchr(buffer, ']');
if (!endcmd) {
goto exit;
}
// copy params
blen = (uint32_t)endcmd - (uint32_t)buffer;
oparams = (char*)calloc(blen+2, 1);
if (!oparams) return 4;
params = oparams;
strncpy(oparams, buffer, blen+2);
oparams[blen] = 0;
cmd = endcmd + 1;
for (uint32_t cnt = 0; cnt < MAX_ATTCHMENTS; cnt++) {
attachments[cnt] = 0;
}
num_attachments = 0;
#ifdef DEBUG_EMAIL_PORT
AddLog(LOG_LEVEL_INFO, PSTR("mailsize: %d"),blen);
#endif
mserv = strtok(params, ":");
if (!mserv) {
goto exit;
}
// port
pstr = strtok(NULL, ":");
if (!pstr) {
goto exit;
}
#ifdef EMAIL_PORT
if (*pstr == '*') {
port = EMAIL_PORT;
} else {
port = atoi(pstr);
}
#else
port = atoi(pstr);
#endif
user = strtok(NULL, ":");
if (!user) {
goto exit;
}
passwd = strtok(NULL, ":");
if (!passwd) {
goto exit;
}
from = strtok(NULL, ":");
if (!from) {
goto exit;
}
to = strtok(NULL, ":");
if (!to) {
goto exit;
}
subject = strtok(NULL, "]");
if (!subject) {
goto exit;
}
#ifdef EMAIL_USER
if (*user == '*') {
user = xPSTR(EMAIL_USER);
}
#endif
#ifdef EMAIL_PASSWORD
if (*passwd == '*') {
passwd = xPSTR(EMAIL_PASSWORD);
}
#endif
#ifdef EMAIL_SERVER
if (*mserv == '*') {
mserv = xPSTR(EMAIL_SERVER);
}
#endif
#ifdef DEBUG_EMAIL_PORT
AddLog_P(LOG_LEVEL_INFO, PSTR("%s - %d - %s - %s"), mserv, port, user, passwd);
#endif
#ifdef EMAIL_FROM
if (*from == '*') {
from = xPSTR(EMAIL_FROM);
}
#endif
#ifdef DEBUG_EMAIL_PORT
AddLog_P(LOG_LEVEL_INFO, PSTR("%s - %s - %s - %s"), from, to, subject, cmd);
#endif
smtp.debug(true);
//smtp.debug(false);
message.clearRecipients();
message.clearCc();
message.clearBcc();
//smtp.callback(smtpCallback);
session.server.host_name = mserv;
session.server.port = port;
session.login.email = user;
session.login.password = passwd;
session.login.user_domain = "googlemail.com";
message.enable.chunking = true;
char sname[32];
strlcpy(sname, SettingsText(SET_FRIENDLYNAME1), sizeof(sname));
message.sender.name = sname;
message.sender.email = from;
message.subject = subject;
message.addRecipient("user1", to);
message.html.charSet = "utf-8";
message.text.charSet = "utf-8";
message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64;
message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal;
//message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay;
message.response.notify = esp_mail_smtp_notify_failure;
message.html.charSet = "us-ascii";
message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit;
message.addHeader("Message-ID: <user1@gmail.com>");
#ifdef USE_SCRIPT
if (*cmd == '*' && *(cmd + 1) == 0) {
script_send_email_body(send_message_txt);
} else {
html_content += cmd;
message.html.content = html_content.c_str();
}
#else
html_content += cmd;
message.html.content = html_content.c_str();
#endif
/* Connect to server with the session config */
delay(0);
if (!smtp.connect(&session))
goto exit;
/* Start sending the Email and close the session */
delay(0);
if (!MailClient.sendMail(&smtp, &message, true)) {
Serial.println("Error sending Email, " + smtp.errorReason());
}
exit:
for (uint32_t cnt = 0; cnt < MAX_ATTCHMENTS; cnt++) {
if (attachments[cnt]) {
free(attachments[cnt]);
attachments[cnt] = 0;
}
}
html_content = "";
if (oparams) free(oparams);
return status;
}
void send_message_txt(char *txt) {
if (*txt == '@') {
txt++;
attach_File(txt);
} else if (*txt == '&') {
txt++;
attach_Array(txt);
} else if (*txt == '$') {
txt++;
#if defined(ESP32) && defined(USE_WEBCAM)
if (num_attachments < MAX_ATTCHMENTS) {
attachments[num_attachments] = (char*)malloc(32);
uint32_t cnt;
uint8_t *buff;
uint32_t len, picmax;
picmax = WcGetPicstore(-1, 0);
cnt = *txt&7;
if (cnt < 1 || cnt > picmax) cnt = 1;
len = WcGetPicstore(cnt - 1, &buff);
if (len) {
sprintf(attachments[num_attachments], "img_%1d.jpg", cnt);
attach_Data(attachments[num_attachments], buff, len);
}
num_attachments++;
}
#endif
} else {
html_content += txt;
email_mptr->html.content = html_content.c_str();
}
}
void attach_File(char *path) {
SMTP_Attachment att;
if (num_attachments < MAX_ATTCHMENTS) {
attachments[num_attachments] = (char*)malloc(32);
strcpy(attachments[num_attachments], path);
char *cp = attachments[num_attachments];
att.file.path = cp;
if (*cp == '/') {
cp++;
}
att.descr.filename = cp;
att.descr.mime = "application/octet-stream"; //binary data
att.file.storage_type = esp_mail_file_storage_type_univ;
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;
email_mptr->addAttachment(att);
email_mptr->resetAttachItem(att);
num_attachments++;
}
}
float *get_array_by_name(char *name, uint16_t *alen);
void flt2char(float num, char *nbuff);
void attach_Array(char *aname) {
float *array = 0;
uint16_t alen;
String ttstr = "";
array = get_array_by_name(aname, &alen);
if (array && alen) {
float *fp = array;
for (uint32_t cnt = 0; cnt < alen; cnt++) {
// export array as tab gelimited text
char nbuff[16];
flt2char(*fp++, nbuff);
if (cnt < (alen - 1)) {
strcat(nbuff, "\t");
} else {
strcat(nbuff, "\n");
}
ttstr += nbuff;
}
if (num_attachments < MAX_ATTCHMENTS) {
attachments[num_attachments] = (char*)malloc(ttstr.length() + 1 + 32);
strcpy(attachments[num_attachments] + 32, ttstr.c_str());
sprintf(attachments[num_attachments], "%s.txt", aname);
attach_Data(attachments[num_attachments], (uint8_t*)attachments[num_attachments]+32, ttstr.length());
num_attachments++;
}
} else {
//g_client->print(F("\r\n\r\narray not found!\r\n"));
}
}
void attach_Data(char *name, uint8_t *buff, uint32_t len) {
SMTP_Attachment att;
att.descr.filename = name;
att.descr.mime = "application/octet-stream";
att.blob.data = buff;
att.blob.size = len;
att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;
email_mptr->addAttachment(att);
email_mptr->resetAttachItem(att);
}
#endif // USE_ESP32MAIL

View File

@ -3,17 +3,8 @@
//#define DEBUG_EMAIL_PORT
//#include <WiFiClient.h>
//#include <WiFiClientSecure.h>
#include <base64.h>
//#include <core_version.h>
#ifdef ESP8266
#include "WiFiClientSecureLightBearSSL.h"
#endif // ESP8266
#ifdef ESP32
#include <WiFiClientSecure.h>
#endif // ESP32
class SendEmail
{
@ -25,13 +16,8 @@ class SendEmail
const int timeout;
const bool ssl;
const int auth_used;
#ifdef ESP8266
// use bear ssl
BearSSL::WiFiClientSecure_light *client;
#endif // ESP8266
#ifdef ESP32
WiFiClient *client;
#endif // ESP32
String readClient();
void a3_to_a4(unsigned char * a4, unsigned char * a3);

View File

@ -1,8 +1,6 @@
#ifdef USE_SENDMAIL
#ifndef USE_ESP32MAIL
#include "sendemail.h"
#include "sendemail_ESP8266.h"
// enable serial debugging
//#define DEBUG_EMAIL_PORT
@ -179,19 +177,10 @@ exit:
}
#ifdef ESP8266
WiFiClient *g_client;
SendEmail::SendEmail(const String& host, const int port, const String& user, const String& passwd, const int timeout, const int auth_used) :
host(host), port(port), user(user), passwd(passwd), timeout(timeout), ssl(ssl), auth_used(auth_used), client(new BearSSL::WiFiClientSecure_light(1024,1024)) {
}
#endif // ESP8266
#ifdef ESP32
WiFiClient *g_client;
SendEmail::SendEmail(const String& host, const int port, const String& user, const String& passwd, const int timeout, const int auth_used) :
host(host), port(port), user(user), passwd(passwd), timeout(timeout), ssl(ssl), auth_used(auth_used), client(new WiFiClientSecure()) {
}
#endif // ESP32
String SendEmail::readClient() {
delay(0);
@ -385,11 +374,14 @@ exit:
return status;
}
#ifdef USE_SCRIPT
void xsend_message_txt(char *msg) {
#ifdef DEBUG_EMAIL_PORT
AddLog_P(LOG_LEVEL_INFO, PSTR("%s"),msg);
#endif
#if (defined(USE_SCRIPT_FATFS) && defined(USE_SCRIPT)) || defined(USE_UFILESYS)
#ifdef USE_UFILESYS
if (*msg=='@') {
msg++;
attach_File(msg);
@ -415,43 +407,6 @@ void xsend_message_txt(char *msg) {
#endif
}
#if (defined(USE_SCRIPT_FATFS) && defined(USE_SCRIPT)) || defined(USE_UFILESYS)
#ifdef ESP8266
#include <LittleFS.h>
#endif // ESP8266
#ifdef ESP32
#include <LITTLEFS.h>
#endif // ESP32
extern FS *ufsp;
void attach_File(char *path) {
g_client->print(F("--frontier\r\n"));
g_client->print(F("Content-Type: text/plain\r\n"));
char buff[64];
char *cp = path;
while (*cp=='/') cp++;
File file = ufsp->open(path, "r");
if (file) {
sprintf_P(buff,PSTR("Content-Disposition: attachment; filename=\"%s\"\r\n\r\n"), cp);
g_client->write(buff);
uint16_t flen = file.size();
uint8_t fbuff[64];
uint16_t blen = sizeof(fbuff);
while (flen>0) {
file.read(fbuff, blen);
flen -= blen;
g_client->write(fbuff, blen);
if (flen<blen) blen = flen;
}
file.close();
} else {
g_client->print(F("\r\n\r\nfile not found!\r\n"));
}
g_client->print(F("\r\n--frontier\r\n"));
}
#endif // defined(USE_SCRIPT_FATFS) && defined(USE_SCRIPT)
float *get_array_by_name(char *name, uint16_t *alen);
void flt2char(float num, char *nbuff);
@ -490,353 +445,41 @@ void attach_Array(char *aname) {
}
g_client->print(F("\r\n--frontier\r\n"));
}
#else
/*
* Created by K. Suwatchai (Mobizt)
*
* Email: k_suwatchai@hotmail.com
*
* Github: https://github.com/mobizt
*
* Copyright (c) 2019 mobizt
*
*/
//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1
//To receive Email for Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
#include "ESP32_MailClient.h"
#include "SD.h"
//For demo only
//#include "image.h"
#ifndef SEND_MAIL32_MINRAM
#define SEND_MAIL32_MINRAM 30*1024
#endif
void script_send_email_body(void(*func)(char *));
#define xPSTR(a) a
//The Email Sending data object contains config and data to send
SMTPData smtpData;
#define MAX_ATTCHMENTS 8
char *attachments[MAX_ATTCHMENTS];
uint8_t num_attachments;
#ifdef USE_UFILESYS
//Callback function to get the Email sending status
//void sendCallback(SendStatus info);
//#define DEBUG_EMAIL_PORT
#include <LittleFS.h>
extern FS *ufsp;
uint16_t SendMail(char *buffer) {
char *params,*oparams;
const char *mserv;
uint16_t port;
const char *user;
const char *pstr;
const char *passwd;
const char *from;
const char *to;
const char *subject;
const char *cmd;
uint16_t status=1;
uint16_t blen;
char *endcmd;
// return if not enough memory
uint32_t mem=ESP.getFreeHeap();
//AddLog(LOG_LEVEL_INFO, PSTR("heap: %d"),mem);
if (mem<SEND_MAIL32_MINRAM) {
return 4;
void attach_File(char *path) {
g_client->print(F("--frontier\r\n"));
g_client->print(F("Content-Type: text/plain\r\n"));
char buff[64];
char *cp = path;
while (*cp=='/') cp++;
File file = ufsp->open(path, "r");
if (file) {
sprintf_P(buff,PSTR("Content-Disposition: attachment; filename=\"%s\"\r\n\r\n"), cp);
g_client->write(buff);
uint16_t flen = file.size();
uint8_t fbuff[64];
uint16_t blen = sizeof(fbuff);
while (flen>0) {
file.read(fbuff, blen);
flen -= blen;
g_client->write(fbuff, blen);
if (flen<blen) blen = flen;
}
while (*buffer==' ') buffer++;
if (*buffer!='[') {
goto exit;
}
buffer++;
endcmd=strchr(buffer,']');
if (!endcmd) {
goto exit;
}
// copy params
blen=(uint32_t)endcmd-(uint32_t)buffer;
oparams=(char*)calloc(blen+2,1);
if (!oparams) return 4;
params=oparams;
strncpy(oparams,buffer,blen+2);
oparams[blen]=0;
cmd=endcmd+1;
for (uint32_t cnt=0; cnt<MAX_ATTCHMENTS; cnt++) {
attachments[cnt]=0;
}
num_attachments=0;
#ifdef DEBUG_EMAIL_PORT
AddLog(LOG_LEVEL_INFO, PSTR("mailsize: %d"),blen);
#endif
mserv=strtok(params,":");
if (!mserv) {
goto exit;
}
// port
pstr=strtok(NULL,":");
if (!pstr) {
goto exit;
}
#ifdef EMAIL_PORT
if (*pstr=='*') {
port=EMAIL_PORT;
file.close();
} else {
port=atoi(pstr);
g_client->print(F("\r\n\r\nfile not found!\r\n"));
}
#else
port=atoi(pstr);
#endif
user=strtok(NULL,":");
if (!user) {
goto exit;
g_client->print(F("\r\n--frontier\r\n"));
}
passwd=strtok(NULL,":");
if (!passwd) {
goto exit;
}
from=strtok(NULL,":");
if (!from) {
goto exit;
}
to=strtok(NULL,":");
if (!to) {
goto exit;
}
subject=strtok(NULL,"]");
if (!subject) {
goto exit;
}
#ifdef EMAIL_USER
if (*user=='*') {
user=xPSTR(EMAIL_USER);
}
#endif
#ifdef EMAIL_PASSWORD
if (*passwd=='*') {
passwd=xPSTR(EMAIL_PASSWORD);
}
#endif
#ifdef EMAIL_SERVER
if (*mserv=='*') {
mserv=xPSTR(EMAIL_SERVER);
}
#endif
#ifdef DEBUG_EMAIL_PORT
AddLog_P(LOG_LEVEL_INFO, PSTR("%s - %d - %s - %s"),mserv,port,user,passwd);
#endif
#ifdef EMAIL_FROM
if (*from=='*') {
from=xPSTR(EMAIL_FROM);
}
#endif
#ifdef DEBUG_EMAIL_PORT
AddLog_P(LOG_LEVEL_INFO, PSTR("%s - %s - %s - %s"),from,to,subject,cmd);
#endif
smtpData.setDebug(true);
//Set the Email host, port, account and password
smtpData.setLogin(mserv, port, user, passwd);
//For library version 1.2.0 and later which STARTTLS protocol was supported,the STARTTLS will be
//enabled automatically when port 587 was used, or enable it manually using setSTARTTLS function.
//smtpData.setSTARTTLS(true);
//Set the sender name and Email
smtpData.setSender("ESP32",from);
//Set Email priority or importance High, Normal, Low or 1 to 5 (1 is highest)
smtpData.setPriority("High");
//Set the subject
smtpData.setSubject(subject);
#ifdef USE_SCRIPT
if (*cmd=='*' && *(cmd+1)==0) {
smtpData.clrMessage(true);
script_send_email_body(send_message_txt);
} else {
smtpData.setMessage(cmd, true);
}
#else
//Set the message - normal text or html format
smtpData.setMessage(cmd, true);
#endif
//Add recipients, can add more than one recipient
smtpData.addRecipient(to);
//Add attachments, can add the file or binary data from flash memory, file in SD card
//Data from internal memory
//smtpData.addAttachData("firebase_logo.png", "image/png", (uint8_t *)dummyImageData, sizeof dummyImageData);
//Add attach files from SD card
//Comment these two lines, if no SD card connected
//Two files that previousely created.
//smtpData.addAttachFile("/binary_file.dat");
//smtpData.addAttachFile("/text_file.txt");
//Add some custom header to message
//See https://tools.ietf.org/html/rfc822
//These header fields can be read from raw or source of message when it received)
//smtpData.addCustomMessageHeader("Date: Sat, 10 Aug 2019 21:39:56 -0700 (PDT)");
//Be careful when set Message-ID, it should be unique, otherwise message will not store
//smtpData.addCustomMessageHeader("Message-ID: <abcde.fghij@gmail.com>");
//Set the storage types to read the attach files (SD is default)
//smtpData.setFileStorageType(MailClientStorageType::SPIFFS);
/*
#ifdef USE_SCRIPT_FATFS
#if USE_SCRIPT_FATFS<0
smtpData.setFileStorageType(MailClientStorageType::FFat);
#else
smtpData.setFileStorageType(MailClientStorageType::SD);
#endif
#endif
*/
smtpData.setFileStorageType(MailClientStorageType::Univ);
//smtpData.setSendCallback(sendCallback);
//Start sending Email, can be set callback function to track the status
if (!MailClient.sendMail(smtpData)) {
//Serial.println("Error sending Email, " + MailClient.smtpErrorReason());
AddLog(LOG_LEVEL_INFO, PSTR("Error sending Email, %s"), MailClient.smtpErrorReason().c_str());
} else {
status=0;
}
//Clear all data from Email object to free memory
smtpData.empty();
for (uint32_t cnt=0; cnt<MAX_ATTCHMENTS; cnt++) {
if (attachments[cnt]) {
free(attachments[cnt]);
attachments[cnt]=0;
}
}
exit:
if (oparams) free(oparams);
return status;
}
float *get_array_by_name(char *name, uint16_t *alen);
void flt2char(float num, char *nbuff);
void attach_Array(char *aname) {
float *array = 0;
uint16_t alen;
String ttstr = "";
array = get_array_by_name(aname, &alen);
if (array && alen) {
float *fp=array;
for (uint32_t cnt = 0; cnt<alen; cnt++) {
// export array as tab gelimited text
char nbuff[16];
flt2char(*fp++, nbuff);
if (cnt < (alen - 1)) {
strcat(nbuff,"\t");
} else {
strcat(nbuff,"\n");
}
ttstr += nbuff;
}
if (num_attachments<MAX_ATTCHMENTS) {
attachments[num_attachments] = (char*)malloc(ttstr.length()+1);
strcpy(attachments[num_attachments],ttstr.c_str());
char name[32];
sprintf(name,"%s.txt",aname);
smtpData.addAttachData(name, "text/plain",(uint8_t*)attachments[num_attachments],ttstr.length());
num_attachments++;
}
} else {
//g_client->print(F("\r\n\r\narray not found!\r\n"));
}
}
void send_message_txt(char *txt) {
if (*txt=='@') {
txt++;
smtpData.addAttachFile(txt);
} else if (*txt=='&') {
txt++;
attach_Array(txt);
} else if (*txt=='$') {
txt++;
#if defined(ESP32) && defined(USE_WEBCAM)
uint32_t cnt;
uint8_t *buff;
uint32_t len,picmax;
picmax=WcGetPicstore(-1,0);
cnt=*txt&7;
if (cnt<1 || cnt>picmax) cnt=1;
len=WcGetPicstore(cnt-1,&buff);
if (len) {
char str[12];
sprintf(str,"img_%1d.jpg",cnt+1);
smtpData.addAttachData(str, "image/jpg",buff,len);
}
#endif
} else {
smtpData.addMessage(txt);
}
}
/*
//Callback function to get the Email sending status
void sendCallback(SendStatus msg)
{
//Print the current status
Serial.println(msg.info());
//Do something when complete
if (msg.success())
{
Serial.println("----------------");
}
}
*/
#endif
#endif // USE_UFILESYS
#endif // USE_SENDMAIL