How to Send Emails with Attachments on ESP32/ESP8266 (EMailSender v4.0.0 & STARTTLS)

Spread the love

And finally, the updated guide for using EMailSender v4.0.0 on ESP32 and ESP8266! This tutorial covers everything you need to know about sending secure emails from your ESP32 board using the new STARTTLS support on port 587.

After months of development and testing, version 4.0.0 introduces native STARTTLS (port 587) support alongside the existing implicit SSL/TLS (port 465), giving you more flexibility and compatibility with various email providers.

Why STARTTLS Matters

In recent years, email service providers have been tightening security requirements. Gmail, for example, has been pushing users toward port 587 with STARTTLS as the preferred method for sending emails.

The Problem

Previous versions of EMailSender supported:

  • ✅ Port 465 with implicit SSL/TLS (connection encrypted from start)
  • ❌ Port 587 with STARTTLS (connection starts plain, then upgrades to SSL)

This limitation meant that some configurations recommended by modern email providers couldn’t be used effectively.

The Solution

Version 4.0.0 introduces complete STARTTLS support, allowing the library to:

  1. Connect to the SMTP server on port 587 with a plain connection
  2. Send the STARTTLS command
  3. Automatically upgrade the connection to SSL/TLS
  4. Continue secure communication for authentication and email transmission

This makes EMailSender fully compatible with Gmail’s current recommendations and modern SMTP server requirements.

The Advise

Remember that the use of STARTTLS requires additional libraries and resources. If possible, and if it’s not a security-critical application, continue to use the 465 port for SSL/TLS.

What’s New in Version 4.0.0

Major Features

STARTTLS Support (Port 587)

The headline feature! The library now supports the STARTTLS protocol, which is the standard for port 587 connections.

// Enable STARTTLS in EMailSenderKey.h
#define EMAIL_ENABLE_INTERNAL_SSLCLIENT

EMailSender emailSend("your.email@gmail.com", "app_password",
                      "your.email@gmail.com", "Your Name",
                      "smtp.gmail.com", 587);  // Port 587!

emailSend.setEHLOCommand(true);  // Required for STARTTLS

Internal SSLClient Integration

For ESP32 and ESP8266, I’ve integrated a custom SSLClient implementation that handles the STARTTLS upgrade seamlessly. This means:

  • No external libraries required for STARTTLS on ESP32/ESP8266
  • Automatic SSL handshake after STARTTLS command
  • Transparent encryption for all subsequent communication

Enhanced Authentication Methods

The library now supports multiple authentication methods:

  • AUTH LOGIN (default) – Most common method
  • AUTH PLAIN (SASL) – Alternative authentication
  • CRAM-MD5 (ESP32 only) – Challenge-response authentication
// Use different authentication methods
emailSend.setSASLLogin(true);      // AUTH PLAIN
emailSend.setCramMD5Login(true);   // CRAM-MD5 (ESP32)

Improved Error Handling

Better error messages and response codes make debugging easier:

EMailSender::Response resp = emailSend.send("recipient@example.com", message);

if (!resp.status) {
    Serial.print("Error Code: ");
    Serial.println(resp.code);
    Serial.print("Description: ");
    Serial.println(resp.desc);  // Detailed error message
}

Better EHLO/HELO Handling

Modern SMTP servers often return multi-line responses to EHLO commands. The new version handles these properly with the awaitSMTPResponseDrain() method.

Understanding STARTTLS vs SSL/TLS

Let’s clarify the difference between the two encryption methods:

Port 465 – Implicit SSL/TLS

Characteristics:

  • ✅ Connection encrypted from the beginning
  • ✅ Simple to implement
  • ✅ Very secure
  • ❌ Uses a dedicated SSL port (465)

Port 587 – STARTTLS

Characteristics:

  • ✅ Standard submission port (587)
  • ✅ Widely supported by modern servers
  • ✅ Flexible – can fallback to unencrypted if needed
  • ✅ Recommended by Gmail and most providers
  • ⚠️ More complex to implement (now solved!)

Which Should You Use?

For Gmail and most modern providers:

  • Port 587 with STARTTLS is recommended
  • Better compatibility with firewalls
  • Standard SMTP submission port

For maximum compatibility:

  • Both ports work with EMailSender v4.0.0!
  • Choose based on your email provider’s recommendations

Not for performance and resources

However, remember to use STARTTLS; you will need more resources in terms of RAM and Flash, so be aware of this.

Hardware

Here to buy my selection of ESP32 ESP32 Dev Kit v1 - TTGO T-Display 1.14 ESP32 - NodeMCU V3 V2 ESP8266 Lolin32 - NodeMCU ESP-32S - WeMos Lolin32 - WeMos Lolin32 mini - ESP32-CAM programmer - ESP32-CAM bundle - ESP32-WROOM-32 - ESP32-S

Here to buy my selection of ESP32-C3 LuatOS esp32c3 Core - ESP32-C3-DevKitC-02 - ESP32-C3-MINI-1 - WeMos LOLIN C3 PICO - WeMos LOLIN C3 Mini v2.1 - WeMos LOLIN C3 Mini v1.0 - ESP32 S3 Purlple AI-S3 - ESP32 C3 Zero - ESP32 C3 SuperMini

Here to buy my selection of ESP32-S3 ESP32 S3 Purlple AI-S3 - YD-ESP32-S3 - ESP32-S3-DevKitC-1 - ESP32-S3-DevKitC-1 - ESP32-S3 Board 5-inch/7-inch screen - ESP32-S3 Zero

To store logs and a large quantity of data, it is useful to use anSD card.

Also for esp8266.

Here to buy my selection of SD card module AliExpress

Software and Library Setup

Install Libraries

Arduino IDE

  1. Open Arduino IDE
  2. Go to Sketch > Include Library > Manage Libraries
  3. Search for “EMailSender
  4. Click Install

PlatformIO

Add to your platformio.ini:

lib_deps = 
    xreef/EMailSender@^4.0.0

Manual Installation

  1. Download the library from GitHub
  2. Extract to Arduino libraries folder
  3. Restart Arduino IDE

Platform Support

EMailSender v4.0.0 supports a wide range of microcontroller platforms:

PlatformWiFiEthernetSSL/TLSSTARTTLSStatus
ESP32Full Support
ESP8266Full Support
Arduino MegaLimited Memory
Arduino UnoLimited Memory
Arduino SAMDFull Support
STM32✅*With Ethernet
Raspberry Pi Pico WFull Support

* Need a good quantity of ram

Network Interfaces

  • WiFi: ESP32, ESP8266, SAMD (WiFiNINA), Raspberry Pi Pico W
  • Ethernet W5100/W5200/W5500: All platforms
  • Ethernet ENC28J60: All platforms (with UIPEthernet)
  • Ethernet with SSL: SSLClient wrapper for secure connections

Quick Start Guide for GMail

Let’s send your first email with STARTTLS!

Get Gmail App Password

Gmail no longer accepts regular passwords. You need an App Password:

  1. Go to your Google Account
  2. Select Security
  3. Enable 2-Step Verification (if not already enabled)
  4. Go to App Passwordshttps://myaccount.google.com/apppasswords
  5. Generate a new password for “Mail” on your device
  6. Copy the 16-character password (no spaces)

Configure EMailSenderKey.h for STARTTLS

Open EMailSenderKey.h and enable STARTTLS support:

// Enable STARTTLS support for ESP32/ESP8266
#define EMAIL_ENABLE_INTERNAL_SSLCLIENT

// Enable debugging (optional)
// #define EMAIL_SENDER_DEBUG
// #define DEBUG_PRINTER Serial

Basic STARTTLS Example

/*
 * EMailSender v4.0.0 - STARTTLS Test for ESP32
 * 
 * Simple example demonstrating email sending using STARTTLS on port 587
 * Tests the EMailSender library with Gmail SMTP authentication
 * 
 * Author: Renzo Mischianti
 * Website: https://www.mischianti.org
 * 
 * Tutorial and documentation available at:
 * https://www.mischianti.org/category/my-libraries/emailsender-send-email-with-attachments/
 * 
 * EMailSender Library: https://github.com/xreef/EMailSender
 * 
 * This example requires:
 * - ESP32 board
 * - WiFi connection
 * - Gmail account with App Password enabled
 */
#include <WiFi.h>
#include <EMailSender.h>

// WiFi credentials
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

// Gmail configuration
const char* emailAddress = "your.email@gmail.com";
const char* emailPassword = "your 16-char app password";  // No spaces!

// Create EMailSender with Gmail SMTP settings
EMailSender emailSend(emailAddress, emailPassword,
                      emailAddress, "Your Name",
                      "smtp.gmail.com", 587);  // Port 587 for STARTTLS

void setup() {
  Serial.begin(115200);
  Serial.println("EMailSender v4.0.0 - STARTTLS Test");
  
  // Connect to WiFi
  Serial.print("Connecting to WiFi");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi Connected!");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());
  
  // Enable EHLO (required for STARTTLS)
  emailSend.setEHLOCommand(true);
  
  // Prepare email message
  EMailSender::EMailMessage message;
  message.subject = "Test from EMailSender v4.0.0";
  message.message = "Hello! This email was sent using STARTTLS on port 587.";
  message.mime = MIME_TEXT_PLAIN;
  
  // Send email
  Serial.println("\nSending email via STARTTLS (port 587)...");
  EMailSender::Response resp = emailSend.send("recipient@example.com", message);
  
  // Check result
  Serial.println("Response Status:");
  Serial.print("  Code: ");
  Serial.println(resp.code);
  Serial.print("  Description: ");
  Serial.println(resp.desc);
  Serial.print("  Success: ");
  Serial.println(resp.status ? "YES" : "NO");
  
  if (resp.status) {
    Serial.println("\n Email sent successfully!");
  } else {
    Serial.println("\n Email sending failed!");
  }
}

void loop() {
  // Nothing here
}

Expected Output

EMailSender v4.0.0 - STARTTLS Test
Connecting to WiFi.....
WiFi Connected!
IP Address: 192.168.1.66

Sending email via STARTTLS (port 587)...
Response Status:
  Code: 0
  Description: Message sent!
  Success: YES

 Email sent successfully!

Memory Optimization especially for ESP8266

First of all, don’t use STARTTLS on port 587, but implicit SSL/TLS on port 465

Check Available Memory

Always monitor memory during development:

void printMemoryStats() {
  Serial.println("\n=== Memory Stats ===");
  Serial.printf("Free Heap: %d bytes\n", ESP.getFreeHeap());
  Serial.printf("Heap Fragmentation: %d%%\n", ESP.getHeapFragmentation());
  Serial.printf("Max Free Block: %d bytes\n", ESP.getMaxFreeBlockSize());
  Serial.printf("Flash Chip Size: %d bytes\n", ESP.getFlashChipSize());
  Serial.printf("Free Sketch Space: %d bytes\n", ESP.getFreeSketchSpace());
}

void setup() {
  Serial.begin(115200);
  delay(100);
  
  printMemoryStats();  // Check at startup
}

Use PROGMEM for Static Strings

// Bad - uses RAM
const char* subject = "Temperature Alert from ESP8266";

// Good - uses Flash
const char subject[] PROGMEM = "Temperature Alert from ESP8266";

// Use with:
String subjectStr = FPSTR(subject);

Reduce String Concatenation

// Bad - creates many temporary strings
String html = "<html><body>";
html += "<h1>Status</h1>";
html += "<p>Temperature: " + String(temp) + "</p>";
html += "</body></html>";

// Better - pre-calculate size
String html;
html.reserve(200);  // Reserve space upfront
html = "<html><body><h1>Status</h1>";
html += "<p>Temperature: ";
html += temp;
html += "</p></body></html>";

// Best - use F() macro
String html = F("<html><body><h1>Status</h1><p>Temperature: ");
html += temp;
html += F("</p></body></html>");

Limit HTML Complexity

// Simple, memory-friendly HTML
void createSimpleHTML(float temp, float humidity) {
  String html = F("<!DOCTYPE html><html><body>");
  html += F("<h2>Sensor Report</h2>");
  html += F("<p>Temp: ");
  html += String(temp, 1);
  html += F("C</p><p>Humidity: ");
  html += String(humidity, 1);
  html += F("%</p></body></html>");
  
  return html;
}

Use Streaming for Large Data

// Instead of building entire email in memory
void sendStreamedData() {
  // Open file
  File dataFile = LittleFS.open("/data.txt", "r");
  
  // Send in chunks
  EMailSender::FileDescriptior fileDesc;
  fileDesc.filename = "data.txt";
  fileDesc.url = "/data.txt";
  fileDesc.storageType = EMailSender::EMAIL_STORAGE_TYPE_LITTLE_FS;
  
  // EMailSender handles streaming automatically
}

Basic SSL/TLS example

/*
 * EMailSender v4.0.0 - Simple Email Test for ESP32 (No STARTTLS)
 *
 * Basic example demonstrating email sending without STARTTLS
 * Uses standard SMTP connection (typically port 25, 465, or custom ports)
 * Suitable for local mail servers or services that don't require encryption
 *
 * Author: Renzo Mischianti
 * Website: https://www.mischianti.org
 *
 * Tutorial and documentation available at:
 * https://www.mischianti.org/category/my-libraries/emailsender-send-email-with-attachments/
 *
 * EMailSender Library: https://github.com/xreef/EMailSender
 *
 * This example requires:
 * - ESP32 board
 * - WiFi connection
 * - SMTP server that accepts non-encrypted connections
 *
 * Note: This method is less secure than STARTTLS and should only be used
 * with trusted local networks or mail servers that explicitly support it.
 */

#include <WiFi.h>
#include <EMailSender.h>

const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

EMailSender emailSend("alert@gmail.com", "app_password",
                      "alert@gmail.com", "ESP32 Sensor",
                      "smtp.gmail.com", 465);

// Alternative: Using default constructor (Gmail defaults, but without STARTTLS)
// EMailSender emailSend("your@email.com", "your_password");

void setup() {
  Serial.begin(115200);
  Serial.println("EMailSender v4.0.0 - Simple Email Test (No STARTTLS)");

  // Connect to WiFi
  Serial.print("Connecting to WiFi");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi Connected!");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  // DO NOT enable EHLO for non-STARTTLS connections
  // emailSend.setEHLOCommand(false); // This is default

  // Prepare email message
  EMailSender::EMailMessage message;
  message.subject = "Test from EMailSender v4.0.0 (No STARTTLS)";
  message.message = "Hello! This email was sent using a simple SMTP connection without STARTTLS encryption.";
  message.mime = MIME_TEXT_PLAIN;

  // Send email
  Serial.println("\nSending email via simple SMTP...");
  EMailSender::Response resp = emailSend.send("recipient@example.com", message);

  // Check result
  Serial.println("Response Status:");
  Serial.print("  Code: ");
  Serial.println(resp.code);
  Serial.print("  Description: ");
  Serial.println(resp.desc);
  Serial.print("  Success: ");
  Serial.println(resp.status ? "YES" : "NO");

  if (resp.status) {
    Serial.println("\n Email sent successfully!");
  } else {
    Serial.println("\n Email sending failed!");
    Serial.println("\nTroubleshooting:");
    Serial.println("- Check if your SMTP server accepts non-encrypted connections");
    Serial.println("- Verify port number (25 for standard SMTP, or server-specific)");
    Serial.println("- Ensure firewall allows outgoing SMTP traffic");
    Serial.println("- Some providers block port 25 - try alternative ports");
  }
}

void loop() {
  // Nothing here
}


The result become like so.

EMailSender v4.0.0 - Simple Email Test (No STARTTLS)
Connecting to WiFi...
WiFi Connected!
IP Address: 192.168.1.66

Sending email via simple SMTP...
Response Status:
  Code: 0
  Description: Message sent!
  Success: YES

 Email sent successfully!

Advanced examples

HTML Email with Styling

void sendHTMLEmail() {
  EMailSender::EMailMessage message;
  message.subject = "ESP32 Status Report";
  
  // Create HTML content
  String html = "<!DOCTYPE html><html><head>"
                "<style>"
                "body { font-family: Arial, sans-serif; }"
                ".header { background: #4CAF50; color: white; padding: 20px; }"
                ".content { padding: 20px; }"
                ".footer { background: #f1f1f1; padding: 10px; font-size: 12px; }"
                "</style></head><body>"
                "<div class='header'><h1>ESP32 Status Report</h1></div>"
                "<div class='content'>"
                "<h2>Device Information</h2>"
                "<p><strong>IP Address:</strong> " + WiFi.localIP().toString() + "</p>"
                "<p><strong>WiFi Signal:</strong> " + String(WiFi.RSSI()) + " dBm</p>"
                "<p><strong>Free Heap:</strong> " + String(ESP.getFreeHeap()) + " bytes</p>"
                "<p><strong>Uptime:</strong> " + String(millis() / 1000) + " seconds</p>"
                "</div>"
                "<div class='footer'>Sent from ESP32 Device</div>"
                "</body></html>";
  
  message.message = html;
  message.mime = MIME_TEXT_HTML;
  
  EMailSender::Response resp = emailSend.send("recipient@example.com", message);
  
  Serial.println(resp.status ? "Email sent!" : "Failed: " + resp.desc);
}

Temperature Sensor Alert System

#include <WiFi.h>
#include <EMailSender.h>

// DHT sensor (install DHT sensor library)
#include <DHT.h>

#define DHT_PIN 4
#define DHT_TYPE DHT22

DHT dht(DHT_PIN, DHT_TYPE);

const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

EMailSender emailSend("alert@gmail.com", "app_password",
                      "alert@gmail.com", "ESP32 Sensor",
                      "smtp.gmail.com", 587);

const float TEMP_HIGH = 30.0;    // High temperature threshold
const float TEMP_LOW = 15.0;     // Low temperature threshold
const float HUMIDITY_HIGH = 80.0; // High humidity threshold

unsigned long lastEmailTime = 0;
const unsigned long EMAIL_INTERVAL = 300000; // 5 minutes between emails

void sendAlert(String alertType, float temp, float hum);

void setup() {
  Serial.begin(115200);
  dht.begin();
  
  // Connect WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi Connected!");
  
  emailSend.setEHLOCommand(true);
}

void loop() {
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();
  
  if (isnan(temperature) || isnan(humidity)) {
    Serial.println("Failed to read sensor!");
    Serial.println("Set mocked data!");
    // Generate realistic mock data that can trigger alerts
    // Temperature: random between 10°C and 35°C
    temperature = 10.0 + (float)(rand() % 250) / 10.0;  // 10.0 to 35.0
    // Humidity: random between 40% and 90%
    humidity = 40.0 + (float)(rand() % 510) / 10.0;     // 40.0 to 90.0
  }
  
  Serial.printf("Temp: %.1f°C, Humidity: %.1f%%\n", temperature, humidity);
  
  // Check thresholds
  bool needAlert = false;
  String alertType = "";
  
  if (temperature > TEMP_HIGH) {
    needAlert = true;
    alertType = "HIGH TEMPERATURE";
  } else if (temperature < TEMP_LOW) {
    needAlert = true;
    alertType = "LOW TEMPERATURE";
  } else if (humidity > HUMIDITY_HIGH) {
    needAlert = true;
    alertType = "HIGH HUMIDITY";
  }
  
  // Send alert if needed and not sent recently
  if (needAlert && (millis() - lastEmailTime > EMAIL_INTERVAL || lastEmailTime == 0)) {
    Serial.println("Email Alert!");
    sendAlert(alertType, temperature, humidity);
    lastEmailTime = millis();
  }

  // Read sensor every 10 seconds
  delay(10000);
}

void sendAlert(String alertType, float temp, float hum) {
  Serial.println("Sending alert email...");
  
  EMailSender::EMailMessage message;
  message.subject = "⚠️ " + alertType + " ALERT";
  
  String html = "<html><body style='font-family: Arial;'>"
                "<h2 style='color: #d32f2f;'>🚨 " + alertType + "</h2>"
                "<div style='background: #fff3e0; padding: 15px; border-left: 4px solid #ff9800;'>"
                "<p><strong>Temperature:</strong> " + String(temp, 1) + "°C</p>"
                "<p><strong>Humidity:</strong> " + String(hum, 1) + "%</p>"
                "<p><strong>Time:</strong> " + String(millis() / 1000) + " seconds since boot</p>"
                "</div>"
                "<p style='color: #666; font-size: 12px; margin-top: 20px;'>Sent from ESP32 Monitoring System</p>"
                "<p style='color: #999; font-size: 11px;'>Powered by EMailSender library by Renzo Mischianti - "
                "<a href='https://www.mischianti.org' style='color: #1976d2;'>www.mischianti.org</a></p>"
                "</body></html>";
  
  message.message = html;
  message.mime = MIME_TEXT_HTML;
  
  EMailSender::Response resp = emailSend.send("smtp.mischianti@gmail.com", message);
  
  if (resp.status) {
    Serial.println("✅ Alert sent successfully!");
  } else {
    Serial.println("❌ Alert failed: " + resp.desc);
  }
}

An ESP32-based monitoring system that sends automatic email alerts when environmental thresholds are exceeded.

Hardware Setup

#define DHT_PIN 4
#define DHT_TYPE DHT22

DHT dht(DHT_PIN, DHT_TYPE);

DHT22 sensor connected to GPIO 4 for temperature and humidity readings.

Email Configuration

EMailSender emailSend("your@gmail.com", "app_password",
                      "your@gmail.com", "ESP32 Sensor",
                      "smtp.gmail.com", 587);

Gmail SMTP configuration with authentication. Requires Gmail app password (not regular password).

Threshold Configuration

const float TEMP_HIGH = 30.0;
const float TEMP_LOW = 15.0;
const float HUMIDITY_HIGH = 80.0;

const unsigned long EMAIL_INTERVAL = 300000; // 5 minutes

Defines alert thresholds and minimum interval between emails to prevent spam.

Sensor Reading with Fallback

float temperature = dht.readTemperature();
float humidity = dht.readHumidity();

if (isnan(temperature) || isnan(humidity)) {
  // Generate realistic mock data
  temperature = 10.0 + (float)(rand() % 250) / 10.0;  // 10.0-35.0°C
  humidity = 40.0 + (float)(rand() % 510) / 10.0;     // 40.0-90.0%
}

Reads sensor data every 10 seconds. If reading fails, generates realistic mock values for testing.

Alert Logic

if (temperature > TEMP_HIGH) {
  alertType = "HIGH TEMPERATURE";
} else if (temperature < TEMP_LOW) {
  alertType = "LOW TEMPERATURE";
} else if (humidity > HUMIDITY_HIGH) {
  alertType = "HIGH HUMIDITY";
}

if (needAlert && (millis() - lastEmailTime > EMAIL_INTERVAL || lastEmailTime == 0)) {
  sendAlert(alertType, temperature, humidity);
  lastEmailTime = millis();
}

Checks thresholds and sends alert immediately on first trigger, then respects 5-minute cooldown.

HTML Email Format

EMailSender::EMailMessage message;
message.subject = "⚠️ " + alertType + " ALERT";
message.mime = MIME_TEXT_HTML;

String html = "<html><body style='font-family: Arial;'>"
              "<h2 style='color: #d32f2f;'>🚨 " + alertType + "</h2>"
              "<div style='background: #fff3e0; padding: 15px;'>"
              "<p><strong>Temperature:</strong> " + String(temp, 1) + "°C</p>"
              "<p><strong>Humidity:</strong> " + String(hum, 1) + "%</p>"
              "</div></body></html>";

EMailSender::Response resp = emailSend.send("recipient@example.com", message);

Sends styled HTML email with color-coded alerts and formatted sensor data.

If the sensor malfunctions, the system automatically generates realistic mock data to allow testing and development without functioning hardware.

Daily Report Generator

#include <WiFi.h>
#include <EMailSender.h>
#include <time.h>

const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

// NTP settings
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 0;
const int daylightOffset_sec = 3600;

// Report schedule (send at 08:00 AM)
const int REPORT_HOUR = 17;
const int REPORT_MINUTE = 32;

bool reportSentToday = false;

void setup() {
  Serial.begin(115200);
  delay(1000); // Initial stabilization

  // Connect WiFi
  Serial.print("Connecting to WiFi");
  WiFi.begin(ssid, password);
  int attempts = 0;
  while (WiFi.status() != WL_CONNECTED && attempts < 20) {
    delay(500);
    Serial.print(".");
    attempts++;
  }

  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("\nFailed to connect!");
    ESP.restart();
    return;
  }

  Serial.println("\nConnected!");
  Serial.print("IP: ");
  Serial.println(WiFi.localIP());

  delay(1000); // Wait for WiFi stabilization

  // Configure time with retry
  Serial.println("Syncing time...");
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

  // Wait for NTP synchronization
  struct tm timeinfo;
  int retry = 0;
  while (!getLocalTime(&timeinfo) && retry < 10) {
    Serial.print(".");
    delay(1000);
    retry++;
  }

  if (retry >= 10) {
    Serial.println("\nNTP sync failed!");
  } else {
    Serial.println("\nTime synced!");
    Serial.println(&timeinfo, "%Y-%m-%d %H:%M:%S");
  }

  emailSend.setEHLOCommand(true);
  Serial.println("Setup complete");
}

void sendDailyReport(struct tm timeinfo);

void loop() {
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    Serial.println("Failed to obtain time");
    delay(60000);
    return;
  }

  // Print current time and status
  char timeStr[30];
  strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S", &timeinfo);
  Serial.print("Current time: ");
  Serial.print(timeStr);
  Serial.print(" | Next report at: ");
  Serial.print(REPORT_HOUR);
  Serial.print(":");
  Serial.print(REPORT_MINUTE < 10 ? "0" : "");
  Serial.println(REPORT_MINUTE);

  // Check if it's time to send report
  if (timeinfo.tm_hour == REPORT_HOUR &&
      timeinfo.tm_min == REPORT_MINUTE &&
      !reportSentToday) {

    sendDailyReport(timeinfo);
    reportSentToday = true;
  }

  // Reset flag at midnight
  if (timeinfo.tm_hour == 0 && timeinfo.tm_min == 0) {
    reportSentToday = false;
    Serial.println("Report flag reset for new day");
  }

  delay(60000); // Check every minute
}

void sendDailyReport(struct tm timeinfo) {
  Serial.println("Generating daily report...");

  char dateStr[30];
  strftime(dateStr, sizeof(dateStr), "%Y-%m-%d", &timeinfo);

  EMailSender::EMailMessage message;
  message.subject = String("Daily Report - ") + dateStr;

  // Collect system statistics
  String html = "<html><body style='font-family: Arial;'>"
                "<h1>ESP32 Daily Report</h1>"
                "<h3>" + String(dateStr) + "</h3>"
                "<table style='border-collapse: collapse; width: 100%;'>"
                "<tr style='background: #4CAF50; color: white;'>"
                "<th style='padding: 10px; border: 1px solid #ddd;'>Metric</th>"
                "<th style='padding: 10px; border: 1px solid #ddd;'>Value</th>"
                "</tr>"
                "<tr><td style='padding: 8px; border: 1px solid #ddd;'>Uptime</td>"
                "<td style='padding: 8px; border: 1px solid #ddd;'>" +
                String(millis() / 86400000) + " days</td></tr>"
                "<tr><td style='padding: 8px; border: 1px solid #ddd;'>Free Heap</td>"
                "<td style='padding: 8px; border: 1px solid #ddd;'>" +
                String(ESP.getFreeHeap()) + " bytes</td></tr>"
                "<tr><td style='padding: 8px; border: 1px solid #ddd;'>WiFi Signal</td>"
                "<td style='padding: 8px; border: 1px solid #ddd;'>" +
                String(WiFi.RSSI()) + " dBm</td></tr>"
                "<tr><td style='padding: 8px; border: 1px solid #ddd;'>IP Address</td>"
                "<td style='padding: 8px; border: 1px solid #ddd;'>" +
                WiFi.localIP().toString() + "</td></tr>"
                "</table>"
                "<p style='color: #666; font-size: 12px; margin-top: 20px;'>"
                "Automated report from ESP32</p>"
                "</body></html>";

  message.message = html;
  message.mime = MIME_TEXT_HTML;

  EMailSender::Response resp = emailSend.send("manager@example.com", message);

  if (resp.status) {
    Serial.println("✅ Daily report sent!");
  } else {
    Serial.println("❌ Report failed: " + resp.desc);
  }
}

Headers and Global Declarations

This initial section includes necessary libraries and defines global constants and variables.

#include <WiFi.h>
#include <EMailSender.h>
#include <time.h>
  • #include <WiFi.h>: Includes the library for managing the ESP32’s Wi-Fi connection.
  • #include <EMailSender.h>: Includes a custom library for sending emails.
  • #include <time.h>: Includes the library for handling time-related functions.
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";
  • ssid and password: These constants hold the credentials (name and password) for your Wi-Fi network. You need to replace the placeholder values.
// NTP settings
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 0;
const int daylightOffset_sec = 3600;

  • NTP Settings: These constants configure the Network Time Protocol (NTP), which is used to get the correct time from the internet.
    • ntpServer: The address of the time server.
    • gmtOffset_sec: The offset from Greenwich Mean Time (GMT) in seconds.
    • daylightOffset_sec: The offset for daylight saving time (3600 seconds = 1 hour).
// Report schedule (send at 08:00 AM)
const int REPORT_HOUR = 17;
const int REPORT_MINUTE = 32;

bool reportSentToday = false;

  • REPORT_HOUR and REPORT_MINUTE: These constants define the exact time (hour and minute in 24-hour format) when the daily email report should be sent.
  • reportSentToday: This is a boolean flag used to ensure the report is sent only once per day. It’s set to true after sending and reset to false at midnight.

sendDailyReport() Function

This function is responsible for creating the email content and sending it.

  • Generate Subject: It creates a subject line for the email, such as “Daily Report – 2025-10-09”.
  • Create HTML Body: It builds an HTML-formatted string for the email body. This allows for a more visually appealing report with a title, a date, and a table.
  • Collect System Data: The table in the email contains key system metrics:
    • Uptime: How long the ESP32 has been running.
    • Free Heap: The amount of available memory (RAM).
    • WiFi Signal: The strength of the Wi-Fi signal (RSSI).
    • IP Address: The device’s current IP address on the network.
  • Send Email: It uses the emailSend.send() method from the library to send the composed email to a hardcoded recipient ("manager@example.com").
  • Log Status: It prints a success or failure message to the serial monitor based on the result of the sending attempt.

Multiple Attachments

Remember to use FFAT (For Large Files).

EMailSender::FileDescriptior files[3];

files[0].filename = "document.pdf";
files[0].url = "/docs/document.pdf";
files[0].mime = "application/pdf";
files[0].encode64 = true;
files[0].storageType = EMailSender::EMAIL_STORAGE_TYPE_SD;

files[1].filename = "image.png";
files[1].url = "/images/image.png";
files[1].mime = MIME_IMAGE_PNG;
files[1].encode64 = true;
files[1].storageType = EMailSender::EMAIL_STORAGE_TYPE_SD;

files[2].filename = "data.txt";
files[2].url = "/data.txt";
files[2].mime = MIME_TEXT_PLAIN;
files[2].encode64 = false;
files[2].storageType = EMailSender::EMAIL_STORAGE_TYPE_SD;

EMailSender::Attachments attachments;
attachments.number = 3;
attachments.fileDescriptor = files;

EMailSender::Response resp = emailSend.send("recipient@example.com",
                                            message,
                                            attachments);

Attachments from SPIFFS/LittleFS/FFat (ESP32/ESP8266)

#include <SPIFFS.h>

// Initialize SPIFFS
SPIFFS.begin();

EMailSender::FileDescriptior fileDescriptor;
fileDescriptor.filename = "config.json";
fileDescriptor.url = "/config.json";
fileDescriptor.mime = "application/json";
fileDescriptor.encode64 = false;
fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_SPIFFS;

// Or use LittleFS
// fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_LITTLE_FS;

// Or use FFAT
// fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_FFAT;

Attachments from Stream

You can attach data from any Stream source (e.g., generated data, network streams, or custom Stream implementations). This is useful when you want to send dynamic content without saving it to a file system first.

// Example: Create a Stream from dynamic data
Stream* myDataStream = ...; // Your Stream implementation
size_t dataSize = 1024;     // Size of the data in bytes

EMailSender::FileDescriptior fileDescriptor;
fileDescriptor.filename = "sensor_data.csv";
fileDescriptor.mime = "text/csv";
fileDescriptor.encode64 = false;
fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_STREAM;
fileDescriptor.stream = myDataStream;      // Pointer to Stream
fileDescriptor.streamSize = dataSize;      // Size is required!

EMailSender::Attachments attachments;
attachments.number = 1;
attachments.fileDescriptor = &fileDescriptor;

EMailSender::Response resp = emailSend.send("recipient@example.com",
                                            message,
                                            attachments);

Attachments from String (Recommended for Dynamic Content)

The easiest way to attach dynamically generated content. Simply pass a String directly – no need for file systems or Stream wrappers!

// Example 1: JSON attachment
String jsonData = "{\"device\":\"ESP32\",\"temperature\":22.5,\"humidity\":65.3}";

EMailSender::FileDescriptior fileDescriptor;
fileDescriptor.filename = "sensor_data.json";
fileDescriptor.mime = "application/json";
fileDescriptor.encode64 = false;
fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_STRING;
fileDescriptor.content = jsonData;  // ✅ Just assign the String!

EMailSender::Attachments attachments;
attachments.number = 1;
attachments.fileDescriptor = &fileDescriptor;

EMailSender::Response resp = emailSend.send("recipient@example.com",
                                            message,
                                            attachments);
// Example 2: CSV attachment (Excel compatible)
String csvData = "Time,Temperature,Humidity\n";
csvData += "12:00,22.5,65.3\n";
csvData += "13:00,23.1,64.8\n";
csvData += "14:00,22.8,66.1\n";

EMailSender::FileDescriptior fileDescriptor;
fileDescriptor.filename = "readings.csv";
fileDescriptor.mime = "text/csv";
fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_STRING;
fileDescriptor.content = csvData;  // ✅ Simply assign the String!
// Example 3: Multiple String attachments with different MIME types
String jsonData = "{\"device\":\"ESP32\",\"temp\":22.5,\"hum\":65.3}";
String csvData = "Sensor,Value,Unit\nTemperature,22.5,°C\nHumidity,65.3,%\n";
String xmlData = "<?xml version=\"1.0\"?><sensors><temp>22.5</temp><hum>65.3</hum></sensors>";
String txtData = "Device: ESP32\nTemperature: 22.5°C\nHumidity: 65.3%\nStatus: OK\n";

EMailSender::FileDescriptior files[4];

// JSON attachment
files[0].filename = "data.json";
files[0].mime = "application/json";
files[0].storageType = EMailSender::EMAIL_STORAGE_TYPE_STRING;
files[0].content = jsonData;

// CSV attachment (Excel compatible)
files[1].filename = "data.csv";
files[1].mime = "text/csv";
files[1].storageType = EMailSender::EMAIL_STORAGE_TYPE_STRING;
files[1].content = csvData;

// XML attachment
files[2].filename = "config.xml";
files[2].mime = "application/xml";
files[2].storageType = EMailSender::EMAIL_STORAGE_TYPE_STRING;
files[2].content = xmlData;

// Text attachment
files[3].filename = "report.txt";
files[3].mime = "text/plain";
files[3].storageType = EMailSender::EMAIL_STORAGE_TYPE_STRING;
files[3].content = txtData;

EMailSender::Attachments attachments;
attachments.number = 4;
attachments.fileDescriptor = files;

EMailSender::Response resp = emailSend.send("recipient@example.com",
                                            message,
                                            attachments);

Best Practices for String Attachments

  • Memory Management: For large content (>10KB), consider using Stream or file-based storage
  • MIME Types: Always specify the correct MIME type for proper handling by email clients
  • File Names: Use descriptive filenames with proper extensions (.json, .csv, .xml, .txt)
  • Content Validation: Ensure your String content is valid (valid JSON, proper CSV format, etc.)
  • Base64 Encoding: Usually not needed for text content; set encode64 = false

Troubleshooting Common Issues

  • “Error: 220 -> …” or Timeout:
    • Verify that your Ethernet cable is properly connected.
    • Check that the SMTP server (smtp-relay.brevo.com) and port (587) are correct.
    • Ensure your network firewall is not blocking port 587.
  • “Error: 535 -> Authentication failed”:
    • Your credentials (Login or SMTP Key) are incorrect. Double-check the SMTP key from your Brevo dashboard.
    • Make sure your sender email address has been verified in Brevo.
  • SD Card Initialization Failed:
    • Check the wiring of your SD card module.
    • Ensure the SD_CS_PIN is correct and does not conflict with the Ethernet Shield’s CS pin (usually pin 10).

Library Specifications

Supported Platforms

PlatformWiFiEthernetSSL/TLSSTARTTLS
ESP32
ESP8266
Arduino Mega/Uno
Arduino SAMD
STM32
Raspberry Pi Pico (RP2040)

IMPORTANTE – Arduino Mega/Uno e SSL/TLS:

Arduino Mega and Uno DO NOT support SSL/TLS due to severe RAM limitations:

  • Arduino Mega has only 8KB of RAM
  • Arduino Uno has only 2KB of RAM
  • BearSSL for SSL/TLS requires at least 24KB of RAM for encryption buffers

Alternative solutions for Arduino Mega/Uno:

  1. Use non-secure SMTP (port 25) – Works but not recommended
  2. Use a local SMTP relay – Configure a local server that handles SSL
  3. Switch to ESP32/ESP8266 – They have more RAM and native SSL/TLS support
  4. Use Arduino SAMD (MKR WiFi 1010) – Has 32KB RAM and supports SSL/TLS

Arduino Mega/Uno examples in this library use only non-secure SMTP!

Supported Network Interfaces

  • WiFi (ESP32/ESP8266) – WiFiClient / WiFiClientSecure
  • WiFi (SAMD/MBED) – WiFiNINA library
  • Ethernet W5100/W5200/W5500 – Standard Ethernet library
  • Ethernet ENC28J60 – UIPEthernet library
  • Ethernet with SSL – SSLClient wrapper for secure connections

Supported Storage Systems

Internal Storage (Microcontroller Flash)

  • SPIFFS (ESP32, ESP8266)
  • LittleFS (ESP32, ESP8266, RP2040)
  • FFAT (ESP32)
  • SPIFM (SPI Flash with Adafruit_SPIFlash)

External Storage (SD/microSD Cards)

  • SD (Standard SD library)
  • SdFat (Version 1.x for RP2040/ESP8266)
  • SdFat2 (Version 2.x for modern platforms)

Library Features

HTML Email with Multiple Recipients

EMailSender::EMailMessage message;
message.subject = "HTML Email Test";
message.message = "<h1>Hello!</h1><p>This is an <b>HTML</b> email.</p>";
message.mime = MIME_TEXT_HTML;  // Set MIME type to HTML

// Multiple recipients
const char* recipients[] = {
  "recipient1@example.com",
  "recipient2@example.com",
  "recipient3@example.com"
};

EMailSender::Response resp = emailSend.send(recipients, 3, message);

Email with CC and BCC

// Array with To, Cc, and Bcc addresses
const char* allRecipients[] = {
  "to@example.com",      // To (1)
  "cc@example.com",      // Cc (1)
  "bcc@example.com"      // Bcc (1)
};

// send(recipients, numTo, numCc, numBcc, message)
EMailSender::Response resp = emailSend.send(allRecipients, 1, 1, 1, message);

Port 587 (STARTTLS) – Recommended for Gmail

STARTTLS starts with a plain connection and upgrades to encrypted.

// Enable internal SSLClient in EMailSenderKey.h
#define EMAIL_ENABLE_INTERNAL_SSLCLIENT

// Use port 587
EMailSender emailSend("user@gmail.com", "app_password", 
                      "user@gmail.com", "Sender Name",
                      "smtp.gmail.com", 587);

// Enable EHLO (required for STARTTLS)
emailSend.setEHLOCommand(true);

Port 465 (Implicit SSL/TLS)

Connection is encrypted from the start.

// Use WiFiClientSecure (ESP32/ESP8266)
EMailSender emailSend("user@gmail.com", "app_password",
                      "user@gmail.com", "Sender Name", 
                      "smtp.gmail.com", 465);

// No additional configuration needed

Using SSLClient with Ethernet (Arduino/STM32)

For boards without native SSL support:

#define EMAIL_ENABLE_OPENSLAB_SSLCLIENT

// The library will use BearSSL-based SSLClient
// for secure connections over Ethernet

Advanced Features

Custom Authentication Methods

// Use AUTH PLAIN (SASL)
emailSend.setSASLLogin(true);

// Use CRAM-MD5 (ESP32 only)
emailSend.setCramMD5Login(true);

// Disable authentication (open relay)
emailSend.setUseAuth(false);

EHLO Configuration

// Use EHLO instead of HELO (recommended for modern servers)
emailSend.setEHLOCommand(true);

// Set custom identifier for HELO/EHLO
emailSend.setPublicIpDescriptor("mydevice");

Email with Attachments from SD Card

#include <SD.h>

// Initialize SD card
SD.begin(SD_CS_PIN);

// Prepare attachment
EMailSender::FileDescriptior fileDescriptor;
fileDescriptor.filename = "photo.jpg";
fileDescriptor.url = "/photo.jpg";  // Path on SD card
fileDescriptor.mime = MIME_IMAGE_JPG;
fileDescriptor.encode64 = true;  // Base64 encode
fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_SD;

EMailSender::Attachments attachments;
attachments.number = 1;
attachments.fileDescriptor = &fileDescriptor;

// Send email with attachment
EMailSender::Response resp = emailSend.send("recipient@example.com", 
                                            message, 
                                            attachments);

Multiple Attachments

EMailSender::FileDescriptior files[3];

files[0].filename = "document.pdf";
files[0].url = "/docs/document.pdf";
files[0].mime = "application/pdf";
files[0].encode64 = true;
files[0].storageType = EMailSender::EMAIL_STORAGE_TYPE_SD;

files[1].filename = "image.png";
files[1].url = "/images/image.png";
files[1].mime = MIME_IMAGE_PNG;
files[1].encode64 = true;
files[1].storageType = EMailSender::EMAIL_STORAGE_TYPE_SD;

files[2].filename = "data.txt";
files[2].url = "/data.txt";
files[2].mime = MIME_TEXT_PLAIN;
files[2].encode64 = false;
files[2].storageType = EMailSender::EMAIL_STORAGE_TYPE_SD;

EMailSender::Attachments attachments;
attachments.number = 3;
attachments.fileDescriptor = files;

EMailSender::Response resp = emailSend.send("recipient@example.com", 
                                            message, 
                                            attachments);

Attachments from SPIFFS/LittleFS/FFat (ESP32/ESP8266)

#include <SPIFFS.h>

// Initialize SPIFFS
SPIFFS.begin();

EMailSender::FileDescriptior fileDescriptor;
fileDescriptor.filename = "config.json";
fileDescriptor.url = "/config.json";
fileDescriptor.mime = "application/json";
fileDescriptor.encode64 = false;
fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_SPIFFS;

// Or use LittleFS
// fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_LITTLE_FS;

// Or use FFAT
// fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_FFAT;

Storage type SPIFM

There is also support for SPI Flash, but it’s better if you refer to the specified tutorial.

// fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_SPIFM;

Storage type String or Stream

String jsonData = "{\"device\":\"ESP32\",\"temp\":22.5,\"hum\":65.3}";

EMailSender::FileDescriptior files[1];

// JSON attachment
files[0].filename = "data.json";
files[0].mime = "application/json";
files[0].storageType = EMailSender::EMAIL_STORAGE_TYPE_STRING;
files[0].content = jsonData;
Stream* myDataStream = ...; // Your Stream implementation
size_t dataSize = 1024;     // Size of the data in bytes

EMailSender::FileDescriptior fileDescriptor;
fileDescriptor.filename = "sensor_data.csv";
fileDescriptor.mime = "text/csv";
fileDescriptor.encode64 = false;
fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_STREAM;
fileDescriptor.stream = myDataStream;      // Pointer to Stream
fileDescriptor.streamSize = dataSize;      // Size is required!

Common MIME Types for String Attachments

File TypeMIME TypeUsage
JSONapplication/jsonAPI data, sensor readings
CSVtext/csvExcel compatible data
XMLapplication/xmlConfiguration files
Texttext/plainLogs, reports
HTMLtext/htmlFormatted documents
JavaScriptapplication/javascriptCode files

Storage Type Comparison

Storage TypeBest ForComplexityMemory Usage
EMAIL_STORAGE_TYPE_STRING📝 Dynamic text content⭐ Very EasyRAM only
EMAIL_STORAGE_TYPE_STREAM🔄 Custom data sources⭐⭐ MediumRAM streaming
EMAIL_STORAGE_TYPE_SD📁 Large files⭐⭐ MediumSD Card
EMAIL_STORAGE_TYPE_SPIFFS🔧 Small config files⭐⭐ MediumInternal Flash
EMAIL_STORAGE_TYPE_LITTLE_FS📊 Medium files (ESP32/ESP8266)⭐⭐ MediumInternal Flash
EMAIL_STORAGE_TYPE_FFAT📈 Large files (ESP32 only)⭐⭐ MediumInternal Flash

Gmail Configuration

To use Gmail, you need an App Password:

  1. Enable 2-Factor Authentication on your Google account
  2. Go to Google App Passwords
  3. Generate a new app password
  4. Use this 16-character password in your code

Gmail Settings:

  • SMTP Server: smtp.gmail.com
  • Port: 587 (STARTTLS) or 465 (SSL/TLS)
  • Authentication: Required

On ESP32 and ESP8266 you can enable the EMAIL_ENABLE_INTERNAL_SSLCLIENT on EMailSenderKey.h file to use STARTTLS on port 587

// If you want to ENABLE the internal SSLClient wrapper (needed for STARTTLS on port 587)
// instead of relying solely on the native secure client (e.g., WiFiClientSecure for 465),
// uncomment the following define. Enabling it increases flash and RAM usage
// but provides STARTTLS support on non-secure base clients.
//#define EMAIL_ENABLE_INTERNAL_SSLCLIENT

For port 465 and SSL/TLS, ESP32 and ESP8266 don’t need any additional library, but to use with STM32 and Ethernet (or other similar device), you can enable EMAIL_ENABLE_OPENSLAB_SSLCLIENT, a lightweight implementation of SSL.

// Enable integration with OPEnSLab-OSU SSLClient (BearSSL) per AVR/Ethernet o schede che ne hanno bisogno.
// Usa questo backend solo se hai INSTALLATO la libreria esterna "SSLClient" (OPEnSLab-OSU).
// STARTTLS (porta 587) NON è supportato da questo backend; è pensato per TLS implicito (465) su Client non-SSL.
// Di default DISABILITATO: abilitalo nel tuo sketch o nelle build flags definendo
//   - EMAIL_ENABLE_EXTERNAL_SSLCLIENT_OPENSLAB (preferito) oppure
//   - EMAIL_ENABLE_OPENSLAB_SSLCLIENT
// #define EMAIL_ENABLE_OPENSLAB_SSLCLIENT

API Reference

Constructor

EMailSender(const char* email_login, 
            const char* email_password);

EMailSender(const char* email_login, 
            const char* email_password,
            const char* email_from);

EMailSender(const char* email_login, 
            const char* email_password,
            const char* email_from,
            const char* name_from);

EMailSender(const char* email_login, 
            const char* email_password,
            const char* email_from,
            const char* name_from,
            const char* smtp_server,
            uint16_t smtp_port);

Configuration Methods

void setSMTPServer(const char* smtp_server);
void setSMTPPort(uint16_t smtp_port);
void setEMailLogin(const char* email_login);
void setEMailFrom(const char* email_from);
void setNameFrom(const char* name_from);
void setEMailPassword(const char* email_password);

void setUseAuth(bool useAuth);
void setEHLOCommand(bool useEHLO);
void setSASLLogin(bool isSASLLogin);
void setCramMD5Login(bool onoff);  // ESP32 only

void setPublicIpDescriptor(const char* descriptor);
void setAdditionalResponseLineOnConnection(uint8_t numLines);
void setAdditionalResponseLineOnHELO(uint8_t numLines);

Send Methods

// Single recipient
Response send(const char* to, EMailMessage &email, Attachments att = {0, 0});
Response send(String to, EMailMessage &email, Attachments att = {0, 0});

// Multiple recipients (To only)
Response send(const char* to[], byte sizeOfTo, EMailMessage &email, Attachments att = {0, 0});
Response send(String to[], byte sizeOfTo, EMailMessage &email, Attachments att = {0, 0});

// Multiple recipients with Cc
Response send(const char* to[], byte sizeOfTo, byte sizeOfCc, EMailMessage &email, Attachments att = {0, 0});

// Multiple recipients with Cc and Bcc
Response send(const char* to[], byte sizeOfTo, byte sizeOfCc, byte sizeOfCCn, EMailMessage &email, Attachments att = {0, 0});

Data Structures

// Email Message
struct EMailMessage {
    String mime = "text/html";  // or "text/plain"
    String subject;
    String message;
};

// File Descriptor for Attachments
struct FileDescriptior {
    StorageType storageType = EMAIL_STORAGE_TYPE_SD;
    String mime;
    bool encode64 = false;
    String filename;
    String url;  // Path to file
};

// Attachments
struct Attachments {
    byte number;
    FileDescriptior *fileDescriptor;
};

// Response
struct Response {
    String code;
    String desc;
    bool status = false;
};

Storage Types

enum StorageType {
    EMAIL_STORAGE_TYPE_SPIFFS,
    EMAIL_STORAGE_TYPE_LITTLE_FS,
    EMAIL_STORAGE_TYPE_FFAT,
    EMAIL_STORAGE_TYPE_SPIFM,
    EMAIL_STORAGE_TYPE_SD
};

MIME Types

Predefined MIME type constants:

MIME_TEXT_HTML    // "text/html"
MIME_TEXT_PLAIN   // "text/plain"
MIME_IMAGE_JPG    // "image/jpg"
MIME_IMAGE_PNG    // "image/png"

Configuration File (EMailSenderKey.h)

The library uses a configuration file to enable/disable features:

// Enable STARTTLS support with internal SSLClient (ESP32/ESP8266)
#define EMAIL_ENABLE_INTERNAL_SSLCLIENT

// Enable OpenSLab SSLClient for Ethernet shields (Arduino/STM32)
#define EMAIL_ENABLE_OPENSLAB_SSLCLIENT

// Enable attachments support
#define ENABLE_ATTACHMENTS

// Enable date header management
#define MANAGE_DATE_HEADER

// Network type (auto-detected based on platform)
// EMAIL_NETWORK_TYPE can be:
// - NETWORK_ESP8266 (ESP8266 WiFi)
// - NETWORK_ESP32 (ESP32 WiFi)
// - NETWORK_W5100 (Ethernet W5100/W5200/W5500)
// - NETWORK_ENC28J60 (ENC28J60 Ethernet)
// - NETWORK_WiFiNINA (SAMD/Arduino WiFiNINA)
// - etc.

// Storage types
// INTERNAL_STORAGE can be: STORAGE_SPIFFS, STORAGE_LITTLEFS, STORAGE_FFAT
// EXTERNAL_STORAGE can be: STORAGE_SD, STORAGE_SDFAT2

Debug Mode

Enable debugging by uncommenting in EMailSenderKey.h:

#define EMAIL_SENDER_DEBUG
#define DEBUG_PRINTER Serial

This will print detailed SMTP communication to Serial Monitor.

Thanks

  1. ESP32: pinout, specs and Arduino IDE configuration
  2. ESP32: integrated SPIFFS Filesystem
  3. ESP32: manage multiple Serial and logging
  4. ESP32 practical power saving
    1. ESP32 practical power saving: manage WiFi and CPU
    2. ESP32 practical power saving: modem and light sleep
    3. ESP32 practical power saving: deep sleep and hibernation
    4. ESP32 practical power saving: preserve data, timer and touch wake up
    5. ESP32 practical power saving: external and ULP wake up
    6. ESP32 practical power saving: UART and GPIO wake up
  5. ESP32: integrated LittleFS FileSystem
  6. ESP32: integrated FFat (Fat/exFAT) FileSystem
  7. ESP32-wroom-32
    1. ESP32-wroom-32: flash, pinout, specs and IDE configuration
  8. ESP32-CAM
    1. ESP32-CAM: pinout, specs and Arduino IDE configuration
    2. ESP32-CAM: upgrade CamerWebServer with flash features
  9. ESP32: use ethernet w5500 with plain (HTTP) and SSL (HTTPS)
  10. ESP32: use ethernet enc28j60 with plain (HTTP) and SSL (HTTPS)
  11. How to use SD card with esp32
  12. esp32 and esp8266: FAT filesystem on external SPI flash memory
  1. Firmware and OTA update management
    1. Firmware management
      1. ESP32: flash compiled firmware (.bin)
      2. ESP32: flash compiled firmware and filesystem (.bin) with GUI tools
    2. OTA update with Arduino IDE
      1. ESP32 OTA update with Arduino IDE: filesystem, firmware, and password
    3. OTA update with Web Browser
      1. ESP32 OTA update with Web Browser: firmware, filesystem, and authentication
      2. ESP32 OTA update with Web Browser: upload in HTTPS (SSL/TLS) with self-signed certificate
      3. ESP32 OTA update with Web Browser: custom web interface
    4. Self OTA uptate from HTTP server
      1. ESP32 self OTA update firmware from the server
      2. ESP32 self OTA update firmware from the server with version check
      3. ESP32 self-OTA update in HTTPS (SSL/TLS) with trusted self-signed certificate
    5. Non-standard Firmware update
      1. ESP32 firmware and filesystem update from SD card
      2. ESP32 firmware and filesystem update with FTP client
  1. Integrating LAN8720 with ESP32 for Ethernet Connectivity with plain (HTTP) and SSL (HTTPS)
  2. Connecting the EByte E70 to ESP32 c3/s3 devices and a simple sketch example
  3. ESP32-C3: pinout, specs and Arduino IDE configuration
  4. Integrating W5500 with ESP32 Using Core 3: Native Ethernet Protocol Support with SSL and Other Features
  5. Integrating LAN8720 with ESP32 Using Core 3: Native Ethernet Protocol Support with SSL and Other Features
  6. Dallas ds18b20:
  7. Guide to I2C on ESP32: Communication with Heterogeneous 5V and 3.3V Devices, Additional Interface Management and Scanner
  8. Display
  1. How to Send Emails with Attachments on ESP32/ESP8266 (EMailSender v4.0.0 & STARTTLS)
  2. ESP32 High Performance FTP Server: A Deep Dive into the MultiFTPServer Library (v3.x)
  3. HC-SR04 Ultrasonic Sensor with ESP32 and Arduino: Complete Guide
  4. How to connect multiple HC-SR04 sensors with PCF8574 (3 methods)
  5. Fix slow HC-SR04 sensors with PCF8574: the hybrid approach trick [Guide]

Spread the love

Leave a Reply

Your email address will not be published. Required fields are marked *

Exit mobile version