Mail Client 1.2.0

This commit is contained in:
Jason2866 2021-06-03 10:59:44 +02:00
parent 6ee612d5e5
commit acd545f1bf
45 changed files with 2506 additions and 936 deletions

View File

@ -1,4 +1,4 @@
# Mail Client Arduino Library for ESP32 and ESP8266 v 1.0.13
# Mail Client Arduino Library for ESP32 and ESP8266 v 1.2.0
[![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)
@ -10,7 +10,7 @@ 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)
![ESP Mail](/media/images/esp-mail-client.svg)
Copyright (c) 2021 K. Suwatchai (Mobizt).
@ -19,14 +19,14 @@ Copyright (c) 2021 K. Suwatchai (Mobizt).
* 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 secured (with SSL and TLS) and non-secure ports.
* 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).
* Support flash memory and SD card for file storages which can be changed in [**ESP_Mail_FS.h**](/src/ESP_Mail_FS.h).
* Support Ethernet (ESP32 using LAN8720, TLK110 and IP101 Ethernet boards). ESP8266 Ethernet is not yet supported.
* Customizable operating configurations (see the examples for the usages)
## Tested Devices
@ -65,6 +65,108 @@ Go to menu **Files** -> **Examples** -> **ESP-Mail-Client-master** and choose on
## IDE Configuaration for ESP8266 MMU - Adjust the Ratio of ICACHE to IRAM
### Arduino IDE
When you update the ESP8266 Arduino Core SDK to v3.0.0, the memory can be configurable from Arduino IDE board settings.
By default MMU **option 1** was selected, the free Heap can be low and may not suitable for the SSL client usage in this library.
To increase the Heap, choose the MMU **option 3**, 16KB cache + 48KB IRAM and 2nd Heap (shared).
![Arduino IDE config](/media/images/ArduinoIDE.png)
More about MMU settings.
https://arduino-esp8266.readthedocs.io/en/latest/mmu.html
### PlatformIO IDE
When Core SDK v3.0.0 becomes available in PlatformIO,
By default the balanced ratio (32KB cache + 32KB IRAM) configuration is used.
To increase the heap, **PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED** build flag should be assigned in platformio.ini.
At the time of writing, to update SDK to v3.0.0 you can follow these steps.
1. In platformio.ini, edit the config as the following
```ini
[env:d1_mini]
platform = https://github.com/platformio/platform-espressif8266.git
build_flags = -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED
board = d1_mini
framework = arduino
monitor_speed = 115200
```
2. Delete this folder **C:\Users\UserName\\.platformio\platforms\espressif8266@src-?????????????**
3. Delete .pio and .vscode folders in your project.
4. Clean and Compile the project.
The supportedd MMU build flags in PlatformIO.
- **PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48**
16KB cache + 48KB IRAM (IRAM)
- **PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED**
16KB cache + 48KB IRAM and 2nd Heap (shared)
- **PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM32_SECHEAP_NOTSHARED**
16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared)
- **PIO_FRAMEWORK_ARDUINO_MMU_EXTERNAL_128K**
128K External 23LC1024
- **PIO_FRAMEWORK_ARDUINO_MMU_EXTERNAL_1024K**
1M External 64 MBit PSRAM
- **PIO_FRAMEWORK_ARDUINO_MMU_CUSTOM**
Disables default configuration and expects user-specified flags
### Test code for MMU
```cpp
#include <Arduino.h>
#include <umm_malloc/umm_heap_select.h>
void setup()
{
Serial.begin(74880);
HeapSelectIram ephemeral;
Serial.printf("IRAM free: %6d bytes\r\n", ESP.getFreeHeap());
{
HeapSelectDram ephemeral;
Serial.printf("DRAM free: %6d bytes\r\n", ESP.getFreeHeap());
}
}
void loop() {
// put your main code here, to run repeatedly:
}
```
## Usage
@ -77,6 +179,31 @@ The following examples showed the minimum usage which many options are not confi
The examples in the examples folder provide the full options usages.
## Notes
The string in the function's parameters or properties of structured data is the pointer to constant char or char array.
You need to assign the string literal or char array or pointer to constant char to it.
#### Ex.
```cpp
message.sender.name = "My Mail";
message.sender.email = "sender or your Email address";
```
Or using String class
```cpp
String name = "John";
String email = "john@mail.com";
message.sender.name = name.c_str();
message.sender.email = email.c_str();
```
### Send the Email

View File

@ -5,7 +5,7 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 mobizt
*
*/
@ -128,3 +128,20 @@ void loop()
{
}
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" : "");
}
}
}

View File

@ -5,7 +5,7 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 mobizt
*
*/
@ -123,3 +123,20 @@ void loop()
{
}
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" : "");
}
}
}

View File

@ -0,0 +1,307 @@
/**
* This example will send the Email in plain text version using ESP32 and LAN8720 Ethernet module.
*
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2021 mobizt
*
*/
/**
* There are many sources for LAN8720 and ESP32 interconnection on the internet which may
* work for your LAN8720 board.
*
* Some methods worked unless no IP is available.
*
* This modification and interconnection provided in this example are mostly worked as
* the 50 MHz clock was created internally in ESP32 which GPIO 17 is set to be output of this clock
* and feeds to the LAN8720 chip XTAL input.
*
* The on-board LAN8720 50 MHz XTAL chip will be disabled by connect its enable pin or pin 1 to GND.
*
* Please see the images in the folder "modified_LAN8720_board_images" for how to modify the LAN8720 board.
*
* The LAN8720 Ethernet modified board and ESP32 board wiring connection.
*
* ESP32 LAN8720
*
* GPIO17 - EMAC_CLK_OUT_180 nINT/REFCLK - LAN8720 XTAL1/CLKIN 4k7 Pulldown
* GPIO22 - EMAC_TXD1 TX1
* GPIO19 - EMAC_TXD0 TX0
* GPIO21 - EMAC_TX_EN TX_EN
* GPIO26 - EMAC_RXD1 RX1
* GPIO25 - EMAC_RXD0 RX0
* GPIO27 - EMAC_RX_DV CRS
* GPIO23 - MDC MDC
* GPIO18 - MDIO MDIO
* GND GND
* 3V3 VCC
*
*/
//In case of Gmail, to send the Email via port 465 (SSL), less secure app option should be enabled in the account settings. https://myaccount.google.com/lesssecureapps?pli=1
#include <WiFi.h>
#include <ESP_Mail_Client.h>
#ifdef ETH_CLK_MODE
#undef ETH_CLK_MODE
#endif
#define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT //RMII clock output from GPIO17
// Pin# of the enable signal for the external crystal oscillator (-1 to disable)
#define ETH_POWER_PIN -1
// Type of the Ethernet PHY (LAN8720 or TLK110)
#define ETH_TYPE ETH_PHY_LAN8720
// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110)
#define ETH_ADDR 1
// Pin# of the I²C clock signal for the Ethernet PHY
#define ETH_MDC_PIN 23
// Pin# of the I²C IO signal for the Ethernet PHY
#define ETH_MDIO_PIN 18
static bool eth_connected = false;
/** 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);
unsigned long sendMillis = 0;
void WiFiEvent(WiFiEvent_t event)
{
//Do not run any function here to prevent stack overflow or nested interrupt
switch (event)
{
case SYSTEM_EVENT_ETH_START:
Serial.println("ETH Started");
//set eth hostname here
ETH.setHostname("esp32-ethernet");
break;
case SYSTEM_EVENT_ETH_CONNECTED:
Serial.println("ETH Connected");
break;
case SYSTEM_EVENT_ETH_GOT_IP:
Serial.print("ETH MAC: ");
Serial.print(ETH.macAddress());
Serial.print(", IPv4: ");
Serial.print(ETH.localIP());
if (ETH.fullDuplex())
{
Serial.print(", FULL_DUPLEX");
}
Serial.print(", ");
Serial.print(ETH.linkSpeed());
Serial.println("Mbps");
eth_connected = true;
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
Serial.println("ETH Disconnected");
eth_connected = false;
break;
case SYSTEM_EVENT_ETH_STOP:
Serial.println("ETH Stopped");
eth_connected = false;
break;
default:
break;
}
}
void sendMail()
{
/** 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;
/** ########################################################
* Some properties of SMTPSession data and parameters pass to
* SMTP_Message class accept the pointer to constant char
* i.e. const char*.
*
* You may assign a string literal to that properties or function
* like below example.
*
* session.login.user_domain = "mydomain.net";
* session.login.user_domain = String("mydomain.net").c_str();
*
* or
*
* String doman = "mydomain.net";
* session.login.user_domain = domain.c_str();
*
* And
*
* String name = "Jack " + String("dawson");
* String email = "jack_dawson" + String(123) + "@mail.com";
*
* message.addRecipient(name.c_str(), email.c_str());
*
* message.addHeader(String("Message-ID: <abcde.fghij@gmail.com>").c_str());
*
* or
*
* String header = "Message-ID: <abcde.fghij@gmail.com>";
* message.addHeader(header.c_str());
*
* ###########################################################
*/
/* 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");
String textMsg = "This is simple plain text message";
message.text.content = textMsg.c_str();
/** 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 setup()
{
Serial.begin(115200);
Serial.println();
WiFi.onEvent(WiFiEvent);
ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK_MODE);
}
void loop()
{
if (eth_connected && (millis() - sendMillis > 300000 || sendMillis == 0))
{
sendMillis = millis();
sendMail();
}
}
/* 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");
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 KiB

View File

@ -7,7 +7,7 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 mobizt
*
*/

View File

@ -6,7 +6,7 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 mobizt
*
*/
@ -110,6 +110,21 @@ void setup()
/* Declare the session config data */
ESP_Mail_Session session;
/** ########################################################
* Some properties of IMAP_Config and ESP_Mail_Session data
* accept the pointer to constant char i.e. const char*.
*
* You may assign a string literal to that properties like
* below example.
*
* config.storage.saved_path = String("/email_data").c_str();
*
* String folder = "INBOX";
* imap.selectFolder(folder.c_str());
*
* ###########################################################
*/
/* Set the session config */
session.server.host_name = IMAP_HOST;
session.server.port = IMAP_PORT;

View File

@ -8,7 +8,7 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 mobizt
*
*/

View File

@ -7,7 +7,7 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 mobizt
*
*/
@ -111,6 +111,21 @@ void setup()
* Which pin 15 is the CS pin of SD card adapter
*/
/** ########################################################
* Some properties of IMAP_Config and ESP_Mail_Session data
* accept the pointer to constant char i.e. const char*.
*
* You may assign a string literal to that properties like
* below example.
*
* config.search.criteria = String("UID SEARCH ALL").c_str();
*
* String folder = "INBOX";
* imap.selectFolder(folder.c_str());
*
* ###########################################################
*/
/* Set the session config */
session.server.host_name = IMAP_HOST;
session.server.port = IMAP_PORT;
@ -227,7 +242,7 @@ void setup()
printSelectedMailboxInfo(imap);
/* Config to search all messages in the opened mailboax (Search mode) */
config.search.criteria = "UID SEARCH ALL";
config.search.criteria = "UID SEARCH ALL"; // or "UID SEARCH NEW" for recent received messages
/* No message UID provide for fetching */
config.fetch.uid = "";

View File

@ -9,7 +9,7 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 mobizt
*
*/
@ -46,6 +46,9 @@
* To test this using GMail, get the OAuth2.0 access token from this web site
* https://developers.google.com/oauthplayground/
*
* You can use the ESP Signer library to generate OAuth2.0 access token
* The library is available here https://github.com/mobizt/ESP-Signer
*
* 1. Select the following scope (in Step 1) from Gmail API V1
* https://mail.google.com/
* https://mail.google.com/

View File

@ -12,7 +12,7 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 mobizt
*
*/

View File

@ -12,12 +12,14 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 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
//The file systems for flash and sd memory can be changed in ESP_Mail_FS.h.
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>
@ -212,6 +214,39 @@ void setup()
/* Declare the session config data */
ESP_Mail_Session session;
/** ########################################################
* Some properties of SMTPSession data and parameters pass to
* SMTP_Message class accept the pointer to constant char
* i.e. const char*.
*
* You may assign a string literal to that properties or function
* like below example.
*
* session.login.user_domain = "mydomain.net";
* session.login.user_domain = String("mydomain.net").c_str();
*
* or
*
* String doman = "mydomain.net";
* session.login.user_domain = domain.c_str();
*
* And
*
* String name = "Jack " + String("dawson");
* String email = "jack_dawson" + String(123) + "@mail.com";
*
* message.addRecipient(name.c_str(), email.c_str());
*
* message.addHeader(String("Message-ID: <abcde.fghij@gmail.com>").c_str());
*
* or
*
* String header = "Message-ID: <abcde.fghij@gmail.com>";
* message.addHeader(header.c_str());
*
* ###########################################################
*/
/* Set the session config */
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
@ -233,7 +268,8 @@ void setup()
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\">";
String htmlMsg = "<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\">";
message.html.content = htmlMsg.c_str();
/** The HTML text message character set e.g.
* us-ascii

View File

@ -11,7 +11,7 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 mobizt
*
*/

View File

@ -9,7 +9,7 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 mobizt
*
*/

View File

@ -0,0 +1,287 @@
/**
* This example will send the Email with inline images stored in flash memory.
* The message content stores as HTML data in flash memory
*
* 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) 2021 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
//The file systems for flash and sd memory can be changed in ESP_Mail_FS.h.
#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();
Serial.println("Mounting SPIFFS...");
const char *html = "<span style=\"color:#ff0000;\">This message contains 2 inline images.</span><br/><br/><img src=\"cid:image-001\" alt=\"orange image\" width=\"100\" height=\"100\"> <img src=\"cid:image-002\" alt=\"green image\" width=\"100\" height=\"100\">";
const char *orangeImg = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAoUlEQVR42u3RMQ0AMAgAsCFgftHLiQpsENJaaFT+fqwRQoQgRAhChCBECEKECBGCECEIEYIQIQgRghCECEGIEIQIQYgQhCBECEKEIEQIQoQgBCFCECIEIUIQIgQhCBGCECEIEYIQIQhBiBCECEGIEIQIQQhChCBECEKEIEQIQhAiBCFCECIEIUIQghAhCBGCECEIEYIQIUKEIEQIQoQg5LoBGi/oCaOpTXoAAAAASUVORK5CYII=";
const char *greenImg = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAoUlEQVR42u3RAQ0AMAgAoJviyWxtAtNYwzmoQGT/eqwRQoQgRAhChCBECEKECBGCECEIEYIQIQgRghCECEGIEIQIQYgQhCBECEKEIEQIQoQgBCFCECIEIUIQIgQhCBGCECEIEYIQIQhBiBCECEGIEIQIQQhChCBECEKEIEQIQhAiBCFCECIEIUIQghAhCBGCECEIEYIQIUKEIEQIQoQg5LoBBaDPbQYiMoMAAAAASUVORK5CYII=";
#if defined(ESP32)
if (SPIFFS.begin(true))
#elif defined(ESP8266)
if (SPIFFS.begin())
#endif
{
//SPIFFS.format();
if (SPIFFS.exists("/orange.png"))
SPIFFS.remove("/orange.png");
if (SPIFFS.exists("/green.png"))
SPIFFS.remove("/green.png");
if (SPIFFS.exists("/msg.html"))
SPIFFS.remove("/msg.html");
Serial.println("Preparing SPIFFS attachments...");
#if defined(ESP32)
File file = SPIFFS.open("/orange.png", FILE_WRITE);
#elif defined(ESP8266)
File file = SPIFFS.open("/orange.png", "w");
#endif
file.print(orangeImg);
file.close();
#if defined(ESP32)
file = SPIFFS.open("/green.png", FILE_WRITE);
#elif defined(ESP8266)
file = SPIFFS.open("/green.png", "w");
#endif
file.print(greenImg);
file.close();
#if defined(ESP32)
file = SPIFFS.open("/msg.html", FILE_WRITE);
#elif defined(ESP8266)
file = SPIFFS.open("/msg.html", "w");
#endif
file.print(html);
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 message content and inline images stored in flash memory";
message.addRecipient("user1", "####@#####_dot_com");
/* Two alternative content versions are sending in this example e.g. plain text and html */
/* Assign blob data (in flash or ram) as HTML message */
message.html.blob.data = (const uint8_t *)html;
message.html.blob.size = strlen(html);
//Or get the content from file
//message.html.file.name = "/msg.html";
//message.html.file.type = esp_mail_file_storage_type_flash;
/** The content transfer encoding e.g.
* enc_7bit or "7bit" (not encoded)
* enc_qp or "quoted-printable" (encoded) <- not supported for message from blob and file
* 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 HTML text message character set e.g.
* us-ascii
* utf-8
* utf-7
* The default value is utf-8
*/
message.html.charSet = "utf-8";
message.text.content = "This message contains 2 inline images.\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;
/* 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";
att.descr.content_id = "image-001"; //The content id (cid) of orange image in the src tag
/** 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_flash;
/* 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 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.descr.content_id = "image-002"; //The content id (cid) of green image in the src tag
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);
/* 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

@ -11,7 +11,7 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 mobizt
*
*/
@ -25,7 +25,6 @@
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "################"
#define WIFI_PASSWORD "################"
@ -87,6 +86,39 @@ void setup()
/* Declare the session config data */
ESP_Mail_Session session;
/** ########################################################
* Some properties of SMTPSession data and parameters pass to
* SMTP_Message class accept the pointer to constant char
* i.e. const char*.
*
* You may assign a string literal to that properties or function
* like below example.
*
* session.login.user_domain = "mydomain.net";
* session.login.user_domain = String("mydomain.net").c_str();
*
* or
*
* String doman = "mydomain.net";
* session.login.user_domain = domain.c_str();
*
* And
*
* String name = "Jack " + String("dawson");
* String email = "jack_dawson" + String(123) + "@mail.com";
*
* message.addRecipient(name.c_str(), email.c_str());
*
* message.addHeader(String("Message-ID: <abcde.fghij@gmail.com>").c_str());
*
* or
*
* String header = "Message-ID: <abcde.fghij@gmail.com>";
* message.addHeader(header.c_str());
*
* ###########################################################
*/
/* Set the session config */
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
@ -103,7 +135,8 @@ void setup()
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>";
String htmlMsg = "<p>This is the <span style=\"color:#ff0000;\">html text</span> message.</p><p>The message was sent via ESP device.</p>";
message.html.content = htmlMsg.c_str();
/** The html text message character set e.g.
* us-ascii
@ -142,7 +175,6 @@ void setup()
/* Set the custom message header */
message.addHeader("Message-ID: <abcde.fghij@gmail.com>");
/* Connect to server with the session config */
if (!smtp.connect(&session))

View File

@ -14,12 +14,14 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 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
//The file systems for flash and sd memory can be changed in ESP_Mail_FS.h.
#include <Arduino.h>
#if defined(ESP32)
#include <WiFi.h>

View File

@ -11,7 +11,7 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 mobizt
*
*/
@ -205,7 +205,7 @@ void setup()
message.addAttachment(att);
/* Add rfc822 message in the message */
message.addRMessage(rfc822);
message.addMessage(rfc822);
/* Connect to server with the session config */
if (!smtp.connect(&session))

View File

@ -10,7 +10,7 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 mobizt
*
*/

View File

@ -9,7 +9,7 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 mobizt
*
*/
@ -84,6 +84,39 @@ void setup()
/* Declare the session config data */
ESP_Mail_Session session;
/** ########################################################
* Some properties of SMTPSession data and parameters pass to
* SMTP_Message class accept the pointer to constant char
* i.e. const char*.
*
* You may assign a string literal to that properties or function
* like below example.
*
* session.login.user_domain = "mydomain.net";
* session.login.user_domain = String("mydomain.net").c_str();
*
* or
*
* String doman = "mydomain.net";
* session.login.user_domain = domain.c_str();
*
* And
*
* String name = "Jack " + String("dawson");
* String email = "jack_dawson" + String(123) + "@mail.com";
*
* message.addRecipient(name.c_str(), email.c_str());
*
* message.addHeader(String("Message-ID: <abcde.fghij@gmail.com>").c_str());
*
* or
*
* String header = "Message-ID: <abcde.fghij@gmail.com>";
* message.addHeader(header.c_str());
*
* ###########################################################
*/
/* Set the session config */
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
@ -100,7 +133,8 @@ void setup()
message.subject = "Test sending plain text Email";
message.addRecipient("Someone", "####@#####_dot_com");
message.text.content = "This is simple plain text message";
String textMsg = "This is simple plain text message";
message.text.content = textMsg.c_str();
/** The Plain text message character set e.g.
* us-ascii

View File

@ -11,7 +11,7 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 mobizt
*
*/
@ -86,6 +86,39 @@ void setup()
/* Declare the session config data */
ESP_Mail_Session session;
/** ########################################################
* Some properties of SMTPSession data and parameters pass to
* SMTP_Message class accept the pointer to constant char
* i.e. const char*.
*
* You may assign a string literal to that properties or function
* like below example.
*
* session.login.user_domain = "mydomain.net";
* session.login.user_domain = String("mydomain.net").c_str();
*
* or
*
* String doman = "mydomain.net";
* session.login.user_domain = domain.c_str();
*
* And
*
* String name = "Jack " + String("dawson");
* String email = "jack_dawson" + String(123) + "@mail.com";
*
* message.addRecipient(name.c_str(), email.c_str());
*
* message.addHeader(String("Message-ID: <abcde.fghij@gmail.com>").c_str());
*
* or
*
* String header = "Message-ID: <abcde.fghij@gmail.com>";
* message.addHeader(header.c_str());
*
* ###########################################################
*/
/* Set the session config */
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
@ -93,7 +126,6 @@ void setup()
session.login.password = AUTHOR_PASSWORD;
session.login.user_domain = "mydomain.net";
/* Declare the message class */
SMTP_Message message;

View File

@ -5,7 +5,7 @@
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2020 mobizt
* Copyright (c) 2021 mobizt
*
*/

View File

@ -33,6 +33,7 @@ setFlag KEYWORD2
addFlag KEYWORD2
removeFlag KEYWORD2
sdBegin KEYWORD2
sdMMCBegin KEYWORD2
connect KEYWORD2
closeSession KEYWORD2
debug KEYWORD2
@ -100,27 +101,27 @@ deleteFolder KEYWORD2
#######################################
# Struct (LITERAL1)
# Struct (KEYWORD3)
#######################################
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_email_info_t KEYWORD3
esp_mail_plain_body_t KEYWORD3
esp_mail_html_body_t KEYWORD3
esp_mail_smtp_msg_response_t KEYWORD3
esp_mail_smtp_enable_option_t KEYWORD3
esp_mail_email_info_t KEYWORD3
esp_mail_folder_info_item_t KEYWORD3
esp_mail_sesson_sever_config_t KEYWORD3
esp_mail_sesson_login_config_t KEYWORD3
esp_mail_sesson_secure_config_t KEYWORD3
esp_mail_sesson_cert_config_t KEYWORD3
esp_mail_imap_fetch_config_t KEYWORD3
esp_mail_imap_search_config_t KEYWORD3
esp_mail_imap_limit_config_t KEYWORD3
esp_mail_imap_enable_config_t KEYWORD3
esp_mail_imap_download_config_t KEYWORD3
esp_mail_imap_storage_config_t KEYWORD3
esp_mail_file_storage_type_none LITERAL1
esp_mail_file_storage_type_flash LITERAL1
esp_mail_file_storage_type_sd LITERAL1
esp_mail_file_storage_type_none KEYWORD3
esp_mail_file_storage_type_flash KEYWORD3
esp_mail_file_storage_type_sd KEYWORD3

View File

@ -1,6 +1,6 @@
{
"name": "ESP Mail Client",
"version": "1.0.13",
"version": "1.2.0",
"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": {

View File

@ -1,9 +1,17 @@
name=ESP Mail Client
version=1.0.13
version=1.2.0
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: 52 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,39 @@
#ifndef ESP_Mail_CONFIG_H
#define ESP_Mail_CONFIG_H
#include <Arduino.h>
/**
* To use other flash file systems
*
* LittleFS File system
*
* #include <LittleFS.h>
* #define ESP_Mail_DEFAULT_FLASH_FS LittleFS //For ESP8266 LitteFS
*
*
* FFat File system
*
* #include <FFat.h>
* #define ESP_Mail_DEFAULT_FLASH_FS FFat //For ESP32 FFat
*
*/
#define ESP_Mail_DEFAULT_FLASH_FS SPIFFS
/**
* To use SD card file systems with different hardware interface
* e.g. SDMMC hardware bus on the ESP32
* https://github.com/espressif/arduino-esp32/tree/master/libraries/SD#faq
*
#include <SD_MMC.h>
#define ESP_Mail_DEFAULT_SD_FS SD_MMC //For ESP32 SDMMC
#define CARD_TYPE_SD_MMC 1
*
*/
#define ESP_Mail_DEFAULT_SD_FS SD
#define CARD_TYPE_SD 1
//For ESP32, format SPIFFS or FFat if mounting failed
#define FORMAT_FLASH_IF_MOUNT_FAILED 1
#endif

View File

@ -1,7 +1,7 @@
# ESP Mail Client Arduino Library for ESP32 and ESP8266
The detail and usage of the available functions in the latest version (1.0.13) are showed below.
The detail and usage of the available functions in the latest version (1.2.0) are showed below.
## Global functions
@ -124,6 +124,25 @@ bool sdBegin(uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss);
#### Initialize the SD_MMC card (ESP32 only).
param **`mountpoint`** The mounting point.
param **`mode1bit`** Allow 1 bit data line (SPI mode).
param **`format_if_mount_failed`** Format SD_MMC card if mount failed.
return **`Boolean`** type status indicates the success of the operation.
```C++
bool sdMMCBegin(const char *mountpoint = "/sdcard", bool mode1bit = false, bool format_if_mount_failed = false);
```
#### Initialize the SD card with the default SPI port.
return **`boolean`** The boolean value which indicates the success of operation.
@ -703,6 +722,10 @@ This property has the sub properties
###### [const char*] content - The PLAIN text content of the message.
###### [esp_mail_blob_message_content_t] blob - The blob that contins PLAIN text content of the message.
###### [esp_mail_file_message_content_t] file - The file that contins PLAIN text content of the message.
###### [const char*] charSet - The character transcoding of the PLAIN text content of the message.
###### [const char*] content_type - The content type of message.
@ -722,6 +745,10 @@ This propery has the sub properties
###### [const char*] content - The HTML content of the message.
###### [esp_mail_blob_message_content_t] blob - The blob that contins HTML content of the message.
###### [esp_mail_file_message_content_t] file - The file that contins HTML content of the message.
###### [const char*] charSet - The character transcoding of the HTML content of the message.
###### [const char*] content_type - The content type of message.
@ -1334,6 +1361,61 @@ esp_mail_smtp_embed_message_type type;
## esp_mail_blob_message_content_t structured data
The following properties are available from the esp_mail_blob_message_content_t data type.
This data type is used for storing the blob info of message body.
##### [Properties] The array of content in flash memory.
```C++
const uint8_t * data;
```
##### [Properties] The array size in bytes.
```C++
size_t size;
```
## esp_mail_file_message_content_t structured data
The following properties are available from the esp_mail_file_message_content_t data type.
This data type is used for storing the file info of message body.
##### [Properties] The file path include its name.
```C++
const char *name;
```
##### [Properties] The type of file storages.
```C++
esp_mail_file_storage_type type;
```
## IMAP_MSG_Item type data

View File

@ -0,0 +1,20 @@
#ifndef _SDK_VERSION_COMMON_H
#define _SDK_VERSION_COMMON_H
#if defined(ESP8266)
#include <string>
//__GNUC__
//__GNUC_MINOR__
//__GNUC_PATCHLEVEL__
#ifdef __GNUC__
#if __GNUC__ > 4 || __GNUC__ == 10
#define ESP8266_CORE_SDK_V3_X_X
#endif
#endif
#endif
#endif

View File

@ -1,8 +1,8 @@
/*
* ESP32 Internet Time Helper Arduino Library v 1.0.1
* ESP8266/ESP32 Internet Time Helper Arduino Library v 1.0.2
*
* 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 returning a copy of
@ -31,12 +31,19 @@
ESPTimeHelper::ESPTimeHelper()
{
}
uint32_t ESPTimeHelper::getUnixTime()
{
uint32_t utime = (msec_time_diff + millis()) / 1000;
return utime;
}
int ESPTimeHelper::setTimestamp(time_t ts)
{
struct timeval tm = {ts, 0};//sec, us
return settimeofday((const timeval *)&tm, 0);
}
time_t ESPTimeHelper::getTimestamp(int year, int mon, int date, int hour, int mins, int sec)
{
struct tm timeinfo;

View File

@ -1,8 +1,8 @@
/*
* ESP8266/ESP32 Internet Time Helper Arduino Library v 1.0.1
* ESP8266/ESP32 Internet Time Helper Arduino Library v 1.0.2
*
* The MIT License (MIT)
* Copyright (c) 2020 K. Suwatchai (Mobizt)
* Copyright (c) 2021 K. Suwatchai (Mobizt)
*
*
* Permission is hereby granted, free of charge, to any person returning a copy of
@ -32,6 +32,7 @@
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#include "SDK_Version_Common.h"
#endif
class ESPTimeHelper
@ -49,6 +50,13 @@ public:
*/
bool setClock(float gmtOffset, float daylightOffset);
/** Set system time with provided timestamp
*
* @param ts timestamp in seconds from midnight Jan 1, 1970.
* @return error number, 0 for success.
*/
int setTimestamp(time_t ts);
/** Provide the Unix time
*
* @return uint32_t The value of current Unix time.

View File

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

View File

@ -1,17 +1,17 @@
/*
* Customized version of ESP32 HTTPClient Library.
*
* v 1.1.1
*
* Customized version of ESP32 HTTPClient Library.
*
* v 1.1.5
*
* 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.
* 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
@ -38,8 +38,6 @@
ESP_Mail_HTTPClient32::ESP_Mail_HTTPClient32()
{
transportTraits = ESP_Mail_TransportTraitsPtr(new ESP_Mail_TLSTraits(nullptr));
_wcs = transportTraits->create();
}
ESP_Mail_HTTPClient32::~ESP_Mail_HTTPClient32()
@ -52,9 +50,6 @@ ESP_Mail_HTTPClient32::~ESP_Mail_HTTPClient32()
}
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)
@ -171,10 +166,10 @@ bool ESP_Mail_HTTPClient32::connect(bool secured)
return true;
}
if (!transportTraits)
return false;
if (_debugCallback)
_wcs->setDebugCB(&_debugCallback);
_wcs->setSTARTTLS(!secured);
transportTraits->verify(*_wcs, _host.c_str(), !secured, _debugCallback);
if (!_wcs->connect(_host.c_str(), _port))
return false;
return connected();
@ -187,14 +182,15 @@ void ESP_Mail_HTTPClient32::setDebugCallback(DebugMsgCallback cb)
void ESP_Mail_HTTPClient32::setCACert(const char *caCert)
{
_wcs->setCACert(caCert);
if (caCert)
{
transportTraits.reset(nullptr);
transportTraits = ESP_Mail_TransportTraitsPtr(new ESP_Mail_TLSTraits(caCert));
_certType = 1;
}
else
{
setInsecure();
_certType = 0;
}
//_wcs->setNoDelay(true);
}
void ESP_Mail_HTTPClient32::setCertFile(const char *caCertFile, esp_mail_file_storage_type storageType)
@ -202,45 +198,34 @@ void ESP_Mail_HTTPClient32::setCertFile(const char *caCertFile, esp_mail_file_st
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 (storageType == esp_mail_file_storage_type_flash)
{
//if (SPIFFS.exists(caCertFile))
// f = SPIFFS.open(caCertFile, FILE_READ);
ESP_MAIL_FLASH_FS.begin();
if (ESP_MAIL_FLASH_FS.exists(caCertFile))
f = ESP_MAIL_FLASH_FS.open(caCertFile, FILE_READ);
}
else if (storageType == esp_mail_file_storage_type::esp_mail_file_storage_type_sd)
else if (storageType == esp_mail_file_storage_type_sd)
{
if (SD.exists(caCertFile))
f = SD.open(caCertFile, FILE_READ);
ESP_MAIL_SD_FS.begin();
if (ESP_MAIL_SD_FS.exists(caCertFile))
f = ESP_MAIL_SD_FS.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);
_wcs->loadCACert(f, len);
f.close();
transportTraits.reset(nullptr);
transportTraits = ESP_Mail_TransportTraitsPtr(new ESP_Mail_TLSTraits(_cacert.get()));
}
_certType = 2;
}
//_wcs->setNoDelay(true);
}
void ESP_Mail_HTTPClient32::setInsecure()
{
_wcs->setInsecure();
}
#endif //ESP32

View File

@ -1,11 +1,11 @@
/*
* Customized version of ESP32 HTTPClient Library.
*
* v 1.1.1
*
* Customized version of ESP32 HTTPClient Library.
*
* v 1.1.5
*
* The MIT License (MIT)
* Copyright (c) 2021 K. Suwatchai (Mobizt)
*
*
* HTTPClient Arduino library for ESP32
*
* Copyright (c) 2015 Markus Sattler. All rights reserved.
@ -39,8 +39,14 @@
#include <FS.h>
//#include <SPIFFS.h>
#include <SD.h>
#include "ESP_Mail_FS.h"
#include "ESP_Mail_WCS32.h"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#define ESP_MAIL_FLASH_FS ESP_Mail_DEFAULT_FLASH_FS
#define ESP_MAIL_SD_FS ESP_Mail_DEFAULT_SD_FS
#if __has_include(<WiFiEspAT.h>) || __has_include(<espduino.h>)
#error WiFi UART bridge was not supported.
#endif
@ -54,56 +60,9 @@ 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
esp_mail_file_storage_type_sd
};
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:
@ -115,7 +74,7 @@ public:
* \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
* If no certificate string provided, use (const char*)NULL to CAcert param
*/
bool begin(const char *host, uint16_t port);
@ -129,7 +88,7 @@ public:
* 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
* \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);
@ -138,7 +97,7 @@ public:
* 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.
* Need to call send with header first.
*/
bool send(const char *header);
@ -148,6 +107,11 @@ public:
*/
WiFiClient *stream(void);
/**
* Set insecure mode
*/
void setInsecure();
ESP_Mail_WCS32 *_stream(void);
size_t _ns_print(const char *buf);
size_t _ns_println(const char *buf);
@ -166,9 +130,7 @@ public:
protected:
DebugMsgCallback _debugCallback = NULL;
ESP_Mail_TransportTraitsPtr transportTraits;
std::unique_ptr<ESP_Mail_WCS32> _wcs;
std::unique_ptr<char> _cacert;
std::unique_ptr<ESP_Mail_WCS32> _wcs = std::unique_ptr<ESP_Mail_WCS32>(new ESP_Mail_WCS32());
std::string _host = "";
uint16_t _port = 0;

View File

@ -1,5 +1,5 @@
/*
*Customized WiFiClientSecure.cpp version 1.0.3
*Customized WiFiClientSecure.cpp version 1.0.8
*
* The MIT License (MIT)
* Copyright (c) 2021 K. Suwatchai (Mobizt)
@ -61,10 +61,11 @@ ESP_Mail_WCS32::ESP_Mail_WCS32()
{
_connected = false;
sslclient = new esp_mail_ssl_ctx32;
ssl_init(sslclient);
sslclient = new esp_mail_ssl_client32::esp_mail_ssl_ctx32;
_ssl_client32.ssl_init(sslclient);
sslclient->socket = -1;
sslclient->handshake_timeout = 120000;
_use_insecure = false;
_CA_cert = NULL;
_cert = NULL;
_private_key = NULL;
@ -78,8 +79,8 @@ ESP_Mail_WCS32::ESP_Mail_WCS32(int sock)
_connected = false;
_timeout = 0;
sslclient = new esp_mail_ssl_ctx32;
ssl_init(sslclient);
sslclient = new esp_mail_ssl_client32::esp_mail_ssl_ctx32;
_ssl_client32.ssl_init(sslclient);
sslclient->socket = sock;
sslclient->handshake_timeout = 120000;
@ -99,10 +100,12 @@ ESP_Mail_WCS32::ESP_Mail_WCS32(int sock)
ESP_Mail_WCS32::ESP_Mail_WCS32(bool secured)
{
_connected = false;
sslclient = new esp_mail_ssl_ctx32;
ssl_init(sslclient);
sslclient = new esp_mail_ssl_client32::esp_mail_ssl_ctx32;
_ssl_client32.ssl_init(sslclient);
sslclient->socket = -1;
sslclient->handshake_timeout = 120000;
_use_insecure = !secured;
_secured = secured;
_CA_cert = NULL;
_cert = NULL;
@ -135,7 +138,7 @@ void ESP_Mail_WCS32::stop()
_connected = false;
_peek = -1;
}
stop_ssl_socket(sslclient, _CA_cert, _cert, _private_key);
_ssl_client32.stop_ssl_socket(sslclient, _CA_cert, _cert, _private_key);
}
int ESP_Mail_WCS32::connect(IPAddress ip, uint16_t port)
@ -164,12 +167,12 @@ int ESP_Mail_WCS32::connect(const char *host, uint16_t port, int32_t 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)
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);
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)
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;
@ -180,7 +183,8 @@ int ESP_Mail_WCS32::connect(const char *host, uint16_t port, const char *_CA_cer
sslclient->handshake_timeout = _timeout;
}
int ret = start_socket(sslclient, host, port, _timeout);
int ret = _ssl_client32.start_socket(sslclient, host, port, _timeout, CA_cert, cert, private_key, NULL, NULL, _use_insecure);
_lastError = ret;
if (ret < 0)
{
@ -191,7 +195,7 @@ int ESP_Mail_WCS32::connect(const char *host, uint16_t port, const char *_CA_cer
if (_secured)
{
ret = start_ssl_client(sslclient, host, port, _timeout, _CA_cert, _cert, _private_key, NULL, NULL);
ret = _ssl_client32.start_ssl_client(sslclient, host, port, _timeout, CA_cert, cert, private_key, NULL, NULL, _use_insecure);
_lastError = ret;
if (ret < 0)
{
@ -207,7 +211,7 @@ int ESP_Mail_WCS32::connect(const char *host, uint16_t port, const char *_CA_cer
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);
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)
@ -221,7 +225,8 @@ int ESP_Mail_WCS32::connect(const char *host, uint16_t port, const char *pskIden
{
sslclient->handshake_timeout = _timeout;
}
int ret = start_socket(sslclient, host, port, _timeout);
int ret = _ssl_client32.start_socket(sslclient, host, port, _timeout, NULL, NULL, NULL, pskIdent, psKey, _use_insecure);
_lastError = ret;
if (ret < 0)
{
@ -232,7 +237,7 @@ int ESP_Mail_WCS32::connect(const char *host, uint16_t port, const char *pskIden
if (_secured)
{
ret = start_ssl_client(sslclient, host, port, _timeout, NULL, NULL, NULL, _pskIdent, _psKey);
ret = _ssl_client32.start_ssl_client(sslclient, host, port, _timeout, NULL, NULL, NULL, pskIdent, psKey, _use_insecure);
_lastError = ret;
if (ret < 0)
{
@ -277,7 +282,7 @@ size_t ESP_Mail_WCS32::write(const uint8_t *buf, size_t size)
{
return 0;
}
int res = send_ssl_data(sslclient, buf, size);
int res = _ssl_client32.send_ssl_data(sslclient, buf, size);
if (res < 0)
{
stop();
@ -312,7 +317,7 @@ int ESP_Mail_WCS32::read(uint8_t *buf, size_t size)
peeked = 1;
}
int res = get_ssl_receive(sslclient, buf, size);
int res = _ssl_client32.get_ssl_receive(sslclient, buf, size);
if (res < 0)
{
stop();
@ -328,7 +333,7 @@ int ESP_Mail_WCS32::available()
{
return peeked;
}
int res = data_to_read(sslclient);
int res = _ssl_client32.data_to_read(sslclient);
if (res < 0)
{
stop();
@ -345,6 +350,16 @@ uint8_t ESP_Mail_WCS32::connected()
return _connected;
}
void ESP_Mail_WCS32::setInsecure()
{
_CA_cert = NULL;
_cert = NULL;
_private_key = NULL;
_pskIdent = NULL;
_psKey = NULL;
_use_insecure = true;
}
void ESP_Mail_WCS32::setCACert(const char *rootCA)
{
_CA_cert = rootCA;
@ -371,17 +386,12 @@ bool ESP_Mail_WCS32::verify(const char *fp, const char *domain_name)
if (!sslclient)
return false;
return verify_ssl_fingerprint(sslclient, fp, domain_name);
return _ssl_client32.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);
char *dest = (char *)malloc(size + 1);
if (!dest)
{
return nullptr;
@ -390,7 +400,9 @@ char *ESP_Mail_WCS32::_streamLoad(Stream &stream, size_t size)
{
free(dest);
dest = nullptr;
return nullptr;
}
dest[size] = '\0';
return dest;
}
@ -436,9 +448,7 @@ int ESP_Mail_WCS32::lastError(char *buf, const size_t size)
{
return 0;
}
char error_buf[100];
mbedtls_strerror(_lastError, error_buf, 100);
snprintf(buf, size, "%s", error_buf);
mbedtls_strerror(_lastError, buf, size);
return _lastError;
}
@ -452,9 +462,9 @@ void ESP_Mail_WCS32::setSTARTTLS(bool enable)
_secured = !enable;
}
void ESP_Mail_WCS32::setDebugCB(DebugMsgCallback cb)
void ESP_Mail_WCS32::setDebugCB(DebugMsgCallback *cb)
{
sslclient->_debugCallback = std::move(cb);
sslclient->_debugCallback = cb;
}
int ESP_Mail_WCS32::_ns_available()
@ -467,7 +477,7 @@ int ESP_Mail_WCS32::_ns_available()
int bufLen = 1024;
char *tmp = new char[bufLen];
memset(tmp, 0, bufLen);
int ret = _ns_lwip_read(sslclient, tmp, bufLen);
int ret = _ssl_client32._ns_lwip_read(sslclient, tmp, bufLen);
if (ret > 0)
_rxBuf += tmp;
delete[] tmp;
@ -481,17 +491,18 @@ int ESP_Mail_WCS32::_ns_available()
}
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);
return _ssl_client32._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);
return _ssl_client32._ns_lwip_read(sslclient, buf, size);
else
{
size_t sz = size;
@ -510,7 +521,7 @@ int ESP_Mail_WCS32::_ns_read()
{
char *buf = new char[2];
memset(buf, 0, 2);
int ret = _ns_lwip_read(sslclient, buf, 1);
int ret = _ssl_client32._ns_lwip_read(sslclient, buf, 1);
if (ret > 0)
c = buf[0];
delete[] buf;
@ -533,9 +544,9 @@ 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);
ret = _ssl_client32.start_ssl_client(sslclient, _host.c_str(), _port, _timeout, _CA_cert, _cert, _private_key, NULL, NULL, _use_insecure);
else if (_withCert)
ret = start_ssl_client(sslclient, _host.c_str(), _port, _timeout, NULL, NULL, NULL, _pskIdent, _psKey);
ret = _ssl_client32.start_ssl_client(sslclient, _host.c_str(), _port, _timeout, NULL, NULL, NULL, _pskIdent, _psKey, _use_insecure);
_lastError = ret;
if (ret < 0)
@ -550,4 +561,4 @@ bool ESP_Mail_WCS32::_ns_connect_ssl()
#endif //ESP32
#endif //WiFiClientSecureESP32_CPP
#endif //ESP_Mail_WCS32_CPP

View File

@ -1,6 +1,6 @@
/*
*Customized WiFiClientSecure.h version 1.0.3
*Customized WiFiClientSecure.h version 1.0.8
*
* The MIT License (MIT)
* Copyright (c) 2021 K. Suwatchai (Mobizt)
@ -58,21 +58,22 @@ typedef void (*DebugMsgCallback)(const char *msg);
class ESP_Mail_WCS32 : public WiFiClient
{
friend class ESP_Mail_HTTPClient32;
protected:
esp_mail_ssl_ctx32 *sslclient;
esp_mail_ssl_client32::esp_mail_ssl_ctx32 *sslclient;
int _lastError = 0;
int _peek = -1;
int _timeout = 0;
bool _use_insecure;
const char *_CA_cert;
const char *_cert;
const char *_private_key;
const char *_pskIdent; // identity for PSK cipher suites
const char *_psKey; // key in hex for PSK cipher suites
DebugMsgCallback _debugCallback = NULL;
public:
friend class ESP_Mail_HTTPClient32;
ESP_Mail_WCS32 *next;
ESP_Mail_WCS32();
ESP_Mail_WCS32(int socket);
@ -96,6 +97,7 @@ public:
void stop();
uint8_t connected();
int lastError(char *buf, const size_t size);
void setInsecure(); // Don't validate the chain, just accept whatever is given. VERY INSECURE!
void setPreSharedKey(const char *pskIdent, const char *psKey); // psKey in Hex
void setCACert(const char *rootCA);
void setCertificate(const char *client_ca);
@ -105,8 +107,9 @@ public:
bool loadPrivateKey(Stream &stream, size_t size);
bool verify(const char *fingerprint, const char *domain_name);
void setHandshakeTimeout(unsigned long handshake_timeout);
int setTimeout(uint32_t seconds) { return 0; }
void setSTARTTLS(bool enable);
void setDebugCB(DebugMsgCallback cb);
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);
@ -139,6 +142,7 @@ public:
}
private:
esp_mail_ssl_client32 _ssl_client32;
char *_streamLoad(Stream &stream, size_t size);
bool _secured = true;
bool _withCert = false;

View File

@ -1,5 +1,5 @@
/*
*Customized ssl_client.cpp to support STARTTLS protocol, version 1.0.5
*Customized ssl_client.cpp to support STARTTLS protocol, version 1.0.8
*
* The MIT License (MIT)
* Copyright (c) 2021 K. Suwatchai (Mobizt)
@ -36,7 +36,8 @@
#ifdef ESP32
#include "Arduino.h"
#include <Arduino.h>
#include <esp32-hal-log.h>
#include <lwip/err.h>
#include <lwip/sockets.h>
@ -49,9 +50,13 @@
#include "esp_mail_ssl_client32.h"
#include <WiFi.h>
const char *_esp_mail_pers32 = "esp32-tls";
#ifndef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
#error "Please configure IDF framework to include mbedTLS -> Enable pre-shared-key ciphersuites and activate at least one cipher"
#endif
static int handle_error(int err)
const char *_esp_mail_pers32 = "esp_mail_esp32-tls";
static int _handle_error(int err, const char *file, int line)
{
if (err == -30848)
{
@ -60,22 +65,32 @@ static int handle_error(int err)
#ifdef MBEDTLS_ERROR_C
char error_buf[100];
mbedtls_strerror(err, error_buf, 100);
log_e("%s", error_buf);
log_e("[%s():%d]: (%d) %s", file, line, err, error_buf);
#else
log_e("[%s():%d]: code %d", file, line, err);
#endif
log_e("MbedTLS message code: %d", err);
return err;
}
void ssl_init(esp_mail_ssl_ctx32 *ssl_client)
#define handle_error(e) _handle_error(e, __FUNCTION__, __LINE__)
void esp_mail_ssl_client32::ssl_init(esp_mail_ssl_ctx32 *ssl_client)
{
mbedtls_ssl_init(&ssl_client->ssl_ctx);
mbedtls_ssl_config_init(&ssl_client->ssl_conf);
mbedtls_ctr_drbg_init(&ssl_client->drbg_ctx);
mbedtls_net_init(&ssl_client->server_fd);
}
int start_socket(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t port, int timeout)
int esp_mail_ssl_client32::start_socket(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, bool insecure)
{
if (rootCABuff == NULL && pskIdent == NULL && psKey == NULL && !insecure)
{
if (ssl_client->_debugCallback)
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_27);
return -1;
}
int enable = 1;
if (ssl_client->_debugCallback)
@ -116,12 +131,23 @@ int start_socket(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t port
{
if (timeout <= 0)
{
timeout = 30000;
timeout = 30000; // Milli seconds.
}
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
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));
timeval so_timeout = {.tv_sec = timeout / 1000, .tv_usec = (timeout % 1000) * 1000};
#define ROE(x, msg) \
{ \
if (((x) < 0)) \
{ \
log_e("LWIP Socket config of " msg " failed."); \
return -1; \
} \
}
ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &so_timeout, sizeof(so_timeout)), "SO_RCVTIMEO");
ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_SNDTIMEO, &so_timeout, sizeof(so_timeout)), "SO_SNDTIMEO");
ROE(lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable)), "TCP_NODELAY");
ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)), "SO_KEEPALIVE");
}
else
{
@ -136,8 +162,9 @@ int start_socket(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t port
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)
int esp_mail_ssl_client32::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, bool insecure)
{
char buf[512];
int ret, flags;
@ -147,21 +174,11 @@ int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t
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 *)_esp_mail_pers32, strlen(_esp_mail_pers32));
ret = mbedtls_ctr_drbg_seed(&ssl_client->drbg_ctx, mbedtls_entropy_func, &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, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
}
ssl_client_send_mbedtls_error_cb(ssl_client, ret);
return handle_error(ret);
}
@ -176,22 +193,22 @@ int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t
MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
{
if (ssl_client->_debugCallback)
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
}
ssl_client_send_mbedtls_error_cb(ssl_client, ret);
return handle_error(ret);
}
// MBEDTLS_SSL_VERIFY_REQUIRED if a CA certificate is defined on Arduino IDE and
// MBEDTLS_SSL_VERIFY_NONE if not.
if (rootCABuff != NULL)
if (insecure)
{
if (ssl_client->_debugCallback)
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_28);
mbedtls_ssl_conf_authmode(&ssl_client->ssl_conf, MBEDTLS_SSL_VERIFY_NONE);
log_i("WARNING: Skipping SSL Verification. INSECURE!");
}
else if (rootCABuff != NULL)
{
if (ssl_client->_debugCallback)
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_11);
@ -204,15 +221,9 @@ int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t
if (ret < 0)
{
if (ssl_client->_debugCallback)
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
}
ssl_client_send_mbedtls_error_cb(ssl_client, ret);
// free the ca_cert in the case parse failed, otherwise, the old ca_cert still in the heap memory, that lead to "out of memory" crash.
mbedtls_x509_crt_free(&ssl_client->ca_cert);
return handle_error(ret);
}
}
@ -229,6 +240,7 @@ int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t
log_e("pre-shared key not valid hex or too long");
return -1;
}
unsigned char psk[MBEDTLS_PSK_MAX_LEN];
size_t psk_len = strlen(psKey) / 2;
for (int j = 0; j < strlen(psKey); j += 2)
@ -257,32 +269,24 @@ int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t
// set mbedtls config
if (ssl_client->_debugCallback)
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)
{
if (ssl_client->_debugCallback)
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
}
ssl_client_send_mbedtls_error_cb(ssl_client, ret);
log_e("mbedtls_ssl_conf_psk returned %d", ret);
return handle_error(ret);
}
}
else
{
mbedtls_ssl_conf_authmode(&ssl_client->ssl_conf, MBEDTLS_SSL_VERIFY_NONE);
log_i("WARNING: Use certificates for a more secure communication!");
return -1;
}
if (cli_cert != NULL && cli_key != NULL)
if (!insecure && cli_cert != NULL && cli_key != NULL)
{
mbedtls_x509_crt_init(&ssl_client->client_cert);
@ -297,15 +301,9 @@ int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t
if (ret < 0)
{
if (ssl_client->_debugCallback)
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
}
ssl_client_send_mbedtls_error_cb(ssl_client, ret);
// free the client_cert in the case parse failed, otherwise, the old client_cert still in the heap memory, that lead to "out of memory" crash.
mbedtls_x509_crt_free(&ssl_client->client_cert);
return handle_error(ret);
}
@ -317,6 +315,8 @@ int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t
if (ret != 0)
{
if (ssl_client->_debugCallback)
ssl_client_send_mbedtls_error_cb(ssl_client, ret);
return handle_error(ret);
}
@ -332,15 +332,7 @@ int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t
if ((ret = mbedtls_ssl_set_hostname(&ssl_client->ssl_ctx, host)) != 0)
{
if (ssl_client->_debugCallback)
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
}
ssl_client_send_mbedtls_error_cb(ssl_client, ret);
return handle_error(ret);
}
@ -349,16 +341,7 @@ int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t
if ((ret = mbedtls_ssl_setup(&ssl_client->ssl_ctx, &ssl_client->ssl_conf)) != 0)
{
if (ssl_client->_debugCallback)
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
}
ssl_client_send_mbedtls_error_cb(ssl_client, ret);
return handle_error(ret);
}
@ -374,20 +357,12 @@ int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
{
if (ssl_client->_debugCallback)
{
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
}
ssl_client_send_mbedtls_error_cb(ssl_client, ret);
return handle_error(ret);
}
if ((millis() - handshake_start_time) > ssl_client->handshake_timeout)
return -1;
vTaskDelay(10 / portTICK_PERIOD_MS);
vTaskDelay(2); //2 ticks
}
if (cli_cert != NULL && cli_key != NULL)
@ -395,7 +370,6 @@ int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t
log_d("Protocol is %s Ciphersuite is %s", mbedtls_ssl_get_version(&ssl_client->ssl_ctx), mbedtls_ssl_get_ciphersuite(&ssl_client->ssl_ctx));
if ((ret = mbedtls_ssl_get_record_expansion(&ssl_client->ssl_ctx)) >= 0)
{
log_d("Record expansion is %d", ret);
}
else
@ -411,18 +385,14 @@ int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t
if ((flags = mbedtls_ssl_get_verify_result(&ssl_client->ssl_ctx)) != 0)
{
bzero(buf, sizeof(buf));
memset(buf, 0, sizeof(buf));
mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags);
if (ssl_client->_debugCallback)
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);
}
else
{
if (ssl_client->_debugCallback)
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_21);
log_v("Certificate verified.");
}
@ -446,10 +416,11 @@ int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t
return ssl_client->socket;
}
void stop_ssl_socket(esp_mail_ssl_ctx32 *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key)
void esp_mail_ssl_client32::stop_ssl_socket(esp_mail_ssl_ctx32 *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key)
{
if (ssl_client->_debugCallback)
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_22);
log_v("Cleaning SSL connection.");
if (ssl_client->socket >= 0)
@ -464,7 +435,7 @@ void stop_ssl_socket(esp_mail_ssl_ctx32 *ssl_client, const char *rootCABuff, con
mbedtls_entropy_free(&ssl_client->entropy_ctx);
}
int data_to_read(esp_mail_ssl_ctx32 *ssl_client)
int esp_mail_ssl_client32::data_to_read(esp_mail_ssl_ctx32 *ssl_client)
{
int ret, res;
ret = mbedtls_ssl_read(&ssl_client->ssl_ctx, NULL, 0);
@ -474,43 +445,33 @@ int data_to_read(esp_mail_ssl_ctx32 *ssl_client)
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret < 0)
{
if (ssl_client->_debugCallback)
{
char *buf = new char[512];
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(ret, error_buf, 100);
strcat(buf, error_buf);
ssl_client->_debugCallback(buf);
delete[] error_buf;
delete[] buf;
}
ssl_client_send_mbedtls_error_cb(ssl_client, ret);
return handle_error(ret);
}
return res;
}
int send_ssl_data(esp_mail_ssl_ctx32 *ssl_client, const uint8_t *data, uint16_t len)
int esp_mail_ssl_client32::send_ssl_data(esp_mail_ssl_ctx32 *ssl_client, const uint8_t *data, size_t len)
{
log_v("Writing HTTP request..."); //for low level debug
log_v("Writing HTTP request with %d bytes...", len); //for low level debug
int ret = -1;
while ((ret = mbedtls_ssl_write(&ssl_client->ssl_ctx, data, len)) <= 0)
{
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret < 0)
{
log_v("Handling error %d", ret); //for low level debug
return handle_error(ret);
}
//wait for space to become available
vTaskDelay(2);
}
len = ret;
//log_v("%d bytes written", len); //for low level debug
return ret;
}
int get_ssl_receive(esp_mail_ssl_ctx32 *ssl_client, uint8_t *data, int length)
int esp_mail_ssl_client32::get_ssl_receive(esp_mail_ssl_ctx32 *ssl_client, uint8_t *data, int length)
{
//log_d( "Reading HTTP response..."); //for low level debug
@ -522,7 +483,7 @@ int get_ssl_receive(esp_mail_ssl_ctx32 *ssl_client, uint8_t *data, int length)
return ret;
}
static bool parseHexNibble(char pb, uint8_t *res)
bool esp_mail_ssl_client32::parseHexNibble(char pb, uint8_t *res)
{
if (pb >= '0' && pb <= '9')
{
@ -543,7 +504,7 @@ static bool parseHexNibble(char pb, uint8_t *res)
}
// Compare a name from certificate and domain name, return true if they match
static bool matchName(const std::string &name, const std::string &domainName)
bool esp_mail_ssl_client32::matchName(const std::string &name, const std::string &domainName)
{
size_t wildcardPos = name.find('*');
if (wildcardPos == std::string::npos)
@ -574,7 +535,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(esp_mail_ssl_ctx32 *ssl_client, const char *fp, const char *domain_name)
bool esp_mail_ssl_client32::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];
@ -588,16 +549,12 @@ bool verify_ssl_fingerprint(esp_mail_ssl_ctx32 *ssl_client, const char *fp, cons
}
if (pos > len - 2)
{
if (ssl_client->_debugCallback)
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;
}
uint8_t high, low;
if (!parseHexNibble(fp[pos], &high) || !parseHexNibble(fp[pos + 1], &low))
{
if (ssl_client->_debugCallback)
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;
}
@ -610,8 +567,6 @@ bool verify_ssl_fingerprint(esp_mail_ssl_ctx32 *ssl_client, const char *fp, cons
if (!crt)
{
if (ssl_client->_debugCallback)
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_25);
log_d("could not fetch peer certificate");
return false;
}
@ -627,8 +582,6 @@ bool verify_ssl_fingerprint(esp_mail_ssl_ctx32 *ssl_client, const char *fp, cons
// Check if fingerprints match
if (memcmp(fingerprint_local, fingerprint_remote, 32))
{
if (ssl_client->_debugCallback)
ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_26);
log_d("fingerprint doesn't match");
return false;
}
@ -641,7 +594,7 @@ bool verify_ssl_fingerprint(esp_mail_ssl_ctx32 *ssl_client, const char *fp, cons
}
// Checks if peer certificate has specified domain in CN or SANs
bool verify_ssl_dn(esp_mail_ssl_ctx32 *ssl_client, const char *domain_name)
bool esp_mail_ssl_client32::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);
@ -688,12 +641,12 @@ bool verify_ssl_dn(esp_mail_ssl_ctx32 *ssl_client, const char *domain_name)
return false;
}
int _ns_lwip_write(esp_mail_ssl_ctx32 *ssl_client, const char *buf, int bufLen)
int esp_mail_ssl_client32::_ns_lwip_write(esp_mail_ssl_ctx32 *ssl_client, const char *buf, int bufLen)
{
return lwip_write(ssl_client->socket, buf, bufLen);
}
int _ns_lwip_read(esp_mail_ssl_ctx32 *ssl_client, char *buf, int bufLen)
int esp_mail_ssl_client32::_ns_lwip_read(esp_mail_ssl_ctx32 *ssl_client, char *buf, int bufLen)
{
fd_set readset;
fd_set writeset;
@ -719,17 +672,31 @@ int _ns_lwip_read(esp_mail_ssl_ctx32 *ssl_client, char *buf, int bufLen)
return read(ssl_client->socket, buf, bufLen);
}
void ssl_client_debug_pgm_send_cb(esp_mail_ssl_ctx32 *ssl_client, PGM_P info)
void esp_mail_ssl_client32::ssl_client_send_mbedtls_error_cb(esp_mail_ssl_ctx32 *ssl_client, int errNo)
{
size_t dbgInfoLen = strlen_P(info) + 1;
char *buf = new char[512];
char *error_buf = new char[100];
memset(buf, 0, 512);
strcpy_P(buf, esp_ssl_client_str_1);
mbedtls_strerror(errNo, error_buf, 100);
strcat(buf, error_buf);
DebugMsgCallback cb = *ssl_client->_debugCallback;
cb(buf);
delete[] error_buf;
delete[] buf;
}
void esp_mail_ssl_client32::ssl_client_debug_pgm_send_cb(esp_mail_ssl_ctx32 *ssl_client, PGM_P info)
{
size_t dbgInfoLen = strlen_P(info) + 10;
char *dbgInfo = new char[dbgInfoLen];
memset(dbgInfo, 0, dbgInfoLen);
strcpy_P(dbgInfo, info);
ssl_client->_debugCallback(dbgInfo);
DebugMsgCallback cb = *ssl_client->_debugCallback;
cb(dbgInfo);
delete[] dbgInfo;
}
#endif //ESP32
#endif //SSL_CLIENT32_CPP
#endif //ESP_MAIL_SSL_CLIENT32_CPP

View File

@ -1,5 +1,5 @@
/*
*Customized ssl_client.h to support STARTTLS protocol, version 1.0.5
*Customized ssl_client.h to support STARTTLS protocol, version 1.0.8
*
* The MIT License (MIT)
* Copyright (c) 2021 K. Suwatchai (Mobizt)
@ -31,14 +31,14 @@
#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>
#include <Arduino.h>
#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";
@ -57,49 +57,62 @@ 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_18[] PROGMEM = "> C: performing the SSL/TLS handshake";
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";
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";
static const char esp_ssl_client_str_27[] PROGMEM = "! E: root certificate, PSK identity or keys are required for secured connection";
static const char esp_ssl_client_str_28[] PROGMEM = "! W: Skipping SSL Verification. INSECURE!";
typedef void (*DebugMsgCallback)(const char *msg);
typedef struct esp_mail_ssl_ctx32
class esp_mail_ssl_client32
{
int socket;
mbedtls_ssl_context ssl_ctx;
mbedtls_ssl_config ssl_conf;
mbedtls_net_context server_fd;
public:
esp_mail_ssl_client32(){};
mbedtls_ctr_drbg_context drbg_ctx;
mbedtls_entropy_context entropy_ctx;
typedef void (*DebugMsgCallback)(const char *msg);
mbedtls_x509_crt ca_cert;
mbedtls_x509_crt client_cert;
mbedtls_pk_context client_key;
DebugMsgCallback _debugCallback;
typedef struct esp_mail_ssl_ctx32
{
int socket;
mbedtls_ssl_context ssl_ctx;
mbedtls_ssl_config ssl_conf;
unsigned long handshake_timeout;
} esp_mail_ssl_ctx32;
mbedtls_ctr_drbg_context drbg_ctx;
mbedtls_entropy_context entropy_ctx;
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);
mbedtls_x509_crt ca_cert;
mbedtls_x509_crt client_cert;
mbedtls_pk_context client_key;
DebugMsgCallback *_debugCallback = NULL;
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, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey, bool insecure);
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, bool insecure);
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, size_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_send_mbedtls_error_cb(esp_mail_ssl_ctx32 *ssl_client, int errNo);
void ssl_client_debug_pgm_send_cb(esp_mail_ssl_ctx32 *ssl_client, PGM_P info);
bool parseHexNibble(char pb, uint8_t *res);
bool matchName(const std::string &name, const std::string &domainName);
};
#endif //ESP32
#endif //SSL_CLIENT32_H
#endif //ESP_MAIL_SSL_CLIENT32_H

View File

@ -1,5 +1,5 @@
/*
* HTTP Client for ESP8266 wrapper v1.0.1
* HTTP Client for ESP8266 wrapper v1.0.3
*
* The MIT License (MIT)
* Copyright (c) 2021 K. Suwatchai (Mobizt)
@ -187,6 +187,7 @@ bool ESP_Mail_HTTPClient::connect(bool secured)
return connected();
}
void ESP_Mail_HTTPClient::setCACert(const char *caCert)
{
@ -224,46 +225,29 @@ void ESP_Mail_HTTPClient::setCertFile(const char *caCertFile, esp_mail_file_stor
if (_clockReady && strlen(caCertFile) > 0)
{
if (storageType == 0)
fs::File f;
if (storageType == esp_mail_file_storage_type_flash)
{
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;
}
}
ESP_MAIL_FLASH_FS.begin();
if (ESP_MAIL_FLASH_FS.exists(caCertFile))
f = ESP_MAIL_FLASH_FS.open(caCertFile, "r");
}
else
else if (storageType == esp_mail_file_storage_type_sd)
{
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);
ESP_MAIL_SD_FS.begin(_sdPin);
if (ESP_MAIL_SD_FS.exists(caCertFile))
f = ESP_MAIL_SD_FS.open(caCertFile, FILE_READ);
}
f.close();
_wcs->setTrustAnchors(new ESP_Mail::ESP_Mail_X509List(der, len));
delete[] der;
}
}
if (f)
{
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;
}

View File

@ -1,20 +1,20 @@
/*
* HTTP Client for ESP8266 wrapper v1.0.1
*
* HTTP Client for ESP8266 wrapper v1.0.3
*
* 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
@ -47,6 +47,9 @@
#include <Arduino.h>
#include <core_version.h>
#include <time.h>
#include <string>
#include "SDK_Version_Common.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.
@ -65,16 +68,11 @@
#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
#include "ESP_Mail_FS.h"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#define FLASH_FS SPIFFS
#endif
#define ESP_MAIL_FLASH_FS ESP_Mail_DEFAULT_FLASH_FS
#define ESP_MAIL_SD_FS ESP_Mail_DEFAULT_SD_FS
#if __has_include(<WiFiEspAT.h>) || __has_include(<espduino.h>)
#error WiFi UART bridge was not supported.
@ -89,8 +87,7 @@ 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
esp_mail_file_storage_type_sd
};
class ESP_Mail_HTTPClient
@ -148,4 +145,4 @@ private:
#endif /* ESP8266 */
#endif /* ESP_Mail_HTTPClient_H */
#endif /* ESP_Mail_HTTPClient_H */

View File

@ -1,6 +1,6 @@
/*
Customized version of WiFiClientSecure.cpp
Customized version of WiFiClientSecure.cpp v1.0.1
WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries
- Mostly compatible with Arduino WiFi shield library and standard
WiFiClient/ServerSecure (except for certificate handling).
@ -53,9 +53,6 @@ extern "C"
#include <c_types.h>
#include <coredecls.h>
//#define Optimistic_yield(A) optimistic_yield(A);ESP.wdtFeed();
#define Optimistic_yield(A) optimistic_yield(A)
#if !CORE_MOCK
// The BearSSL thunks in use for now
@ -262,7 +259,7 @@ namespace ESP_Mail
return 0;
}
_host_name = name;
if (!_secured)
if (!_secured)
return true;
return _connectSSL(name);
}
@ -318,7 +315,7 @@ namespace ESP_Mail
// Ensure we yield if we need multiple fragments to avoid WDT
if (sent_bytes)
{
Optimistic_yield(1000);
optimistic_yield(1000);
}
// Get BearSSL to a state where we can send
@ -522,7 +519,7 @@ namespace ESP_Mail
for (int no_work = 0; blocking || no_work < 2;)
{
Optimistic_yield(100);
optimistic_yield(100);
if (loopTimeout)
{
@ -558,10 +555,10 @@ namespace ESP_Mail
if (!blocking && len > availForWrite)
{
/*
/*
writes on WiFiClient will block if len > availableForWrite()
this is needed to prevent available() calls from blocking
on dropped connections
on dropped connections
*/
len = availForWrite;
}
@ -665,7 +662,7 @@ namespace ESP_Mail
{
_handshake_done = true;
}
Optimistic_yield(1000);
optimistic_yield(1000);
}
return _handshake_done;
}
@ -889,7 +886,6 @@ namespace ESP_Mail
ctx->allow_self_signed = _allow_self_signed ? 1 : 0;
}
// Some constants uses to init the server/client contexts
// Note that suites_P needs to be copied to RAM before use w/BearSSL!
// List copied verbatim from BearSSL/ssl_client_full.c
@ -2012,7 +2008,11 @@ namespace ESP_Mail
return 0;
}
_client->setTimeout(_timeout);
#if defined(ESP8266_CORE_SDK_V3_X_X)
return _client->write((const char *)buf, size);
#else
return _client->write(buf, size);
#endif
}
size_t ESP_Mail_WCS::_ns_write(Stream &stream, size_t unused)
@ -2028,17 +2028,32 @@ namespace ESP_Mail
return 0;
}
_client->setTimeout(_timeout);
#if defined(ESP8266_CORE_SDK_V3_X_X)
size_t dl = stream.available();
uint8_t buf[dl];
stream.readBytes(buf, dl);
return _client->write((const char *)buf, dl);
#else
return _client->write(stream);
#endif
}
size_t ESP_Mail_WCS::_ns_write_P(PGM_P buf, size_t size)
{
if (!_client || !size)
{
return 0;
}
_client->setTimeout(_timeout);
#if defined(ESP8266_CORE_SDK_V3_X_X)
char dest[size];
memcpy_P((void *)dest, (PGM_VOID_P)buf, size);
return _client->write((const char *)dest, size);
#else
return _client->write_P(buf, size);
#endif
}
int ESP_Mail_WCS::_ns_available()
@ -2050,7 +2065,7 @@ namespace ESP_Mail
if (!result)
{
Optimistic_yield(100);
optimistic_yield(100);
}
return result;
}
@ -2119,4 +2134,4 @@ namespace ESP_Mail
#endif /* ESP8266 */
#endif /* ESP_Mail_WCS_CPP */
#endif /* ESP_Mail_WCS_CPP */

View File

@ -1,5 +1,5 @@
/*
Customized version of WiFiClientSecure.h
Customized version of WiFiClientSecure.h v1.0.1
WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries
- Mostly compatible with Arduino WiFi shield library and standard
@ -32,7 +32,7 @@
#include <bearssl/bearssl.h>
#include "ESP_Mail_BearSSLHelpers.h"
#include "ESP_Mail_CertStoreBearSSL.h"
#include "SDK_Version_Common.h"
namespace ESP_Mail {