Come Inviare Email con Allegati da ESP32 e ESP8266 (Guida EMailSender 4.x.x e STARTTLS)

Spread the love

E finalmente, la guida aggiornata per utilizzare EMailSender v4.0.0 su ESP32 e ESP8266! Questo tutorial copre tutto ciò che devi sapere sull’invio di email sicure dalla tua scheda ESP32 utilizzando il nuovo supporto STARTTLS sulla porta 587.

Dopo mesi di sviluppo e test, la versione 4.0.0 introduce il supporto nativo a STARTTLS (porta 587) accanto al supporto esistente per SSL/TLS implicito (porta 465), offrendoti maggiore flessibilità e compatibilità con vari provider di posta elettronica.

Perché STARTTLS è Importante

Negli ultimi anni, i provider di servizi di posta elettronica hanno rafforzato i requisiti di sicurezza. Gmail, ad esempio, ha spinto gli utenti verso la porta 587 con STARTTLS come metodo preferito per l’invio di email.

Il Problema

Le versioni precedenti di EMailSender supportavano:

  • ✅ Porta 465 con SSL/TLS implicito (connessione crittografata dall’inizio)
  • ❌ Porta 587 con STARTTLS (la connessione inizia in chiaro, poi passa a SSL)

Questa limitazione significava che alcune configurazioni raccomandate dai moderni provider di posta elettronica non potevano essere utilizzate efficacemente.

La Soluzione

La versione 4.0.0 introduce il supporto completo a STARTTLS, consentendo alla libreria di:

  1. Connettersi al server SMTP sulla porta 587 con una connessione in chiaro
  2. Inviare il comando STARTTLS
  3. Aggiornare automaticamente la connessione a SSL/TLS
  4. Continuare la comunicazione sicura per l’autenticazione e la trasmissione dell’email

Questo rende EMailSender pienamente compatibile con le attuali raccomandazioni di Gmail e i requisiti dei moderni server SMTP.

Il Consiglio

Ricorda che l’uso di STARTTLS richiede librerie e risorse aggiuntive. Se possibile, e se non si tratta di un’applicazione critica per la sicurezza, continua a utilizzare la porta 465 per SSL/TLS.

Novità della Versione 4.0.0

Funzionalità Principali

Supporto STARTTLS (Porta 587)

La funzionalità di punta! La libreria ora supporta il protocollo STARTTLS, che è lo standard per le connessioni sulla porta 587.

// Abilita STARTTLS in EMailSenderKey.h
#define EMAIL_ENABLE_INTERNAL_SSLCLIENT

EMailSender emailSend("tua.email@gmail.com", "password_app",
                      "tua.email@gmail.com", "Tuo Nome",
                      "smtp.gmail.com", 587);  // Porta 587!

emailSend.setEHLOCommand(true);  // Richiesto per STARTTLS

Integrazione di SSLClient Interno

Per ESP32 ed ESP8266, ho integrato un’implementazione personalizzata di SSLClient che gestisce l’aggiornamento a STARTTLS in modo trasparente. Ciò significa:

  • Nessuna libreria esterna richiesta per STARTTLS su ESP32/ESP8266
  • Handshake SSL automatico dopo il comando STARTTLS
  • Crittografia trasparente per tutte le comunicazioni successive

Metodi di Autenticazione Migliorati

La libreria ora supporta più metodi di autenticazione:

  • AUTH LOGIN (predefinito) – Metodo più comune
  • AUTH PLAIN (SASL) – Autenticazione alternativa
  • CRAM-MD5 (solo ESP32) – Autenticazione challenge-response
// Usa diversi metodi di autenticazione
emailSend.setSASLLogin(true);      // AUTH PLAIN
emailSend.setCramMD5Login(true);   // CRAM-MD5 (ESP32)

Gestione degli Errori Migliorata

Messaggi di errore e codici di risposta migliori rendono il debug più facile:

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

if (!resp.status) {
    Serial.print("Codice Errore: ");
    Serial.println(resp.code);
    Serial.print("Descrizione: ");
    Serial.println(resp.desc);  // Messaggio di errore dettagliato
}

Migliore Gestione di EHLO/HELO

I server SMTP moderni spesso restituiscono risposte su più righe ai comandi EHLO. La nuova versione le gestisce correttamente con il metodo awaitSMTPResponseDrain().

Comprendere STARTTLS vs SSL/TLS

Chiariamo la differenza tra i due metodi di crittografia:

Porta 465 – SSL/TLS Implicito

Caratteristiche:

  • ✅ Connessione crittografata fin dall’inizio
  • ✅ Semplice da implementare
  • ✅ Molto sicuro
  • ❌ Utilizza una porta SSL dedicata (465)

Porta 587 – STARTTLS

Caratteristiche:

  • ✅ Porta di invio standard (587)
  • ✅ Ampiamente supportato dai server moderni
  • ✅ Flessibile – può tornare a non crittografato se necessario
  • ✅ Raccomandato da Gmail e dalla maggior parte dei provider
  • ⚠️ Più complesso da implementare (ora risolto!)

Quale Dovresti Usare?

Per Gmail e la maggior parte dei provider moderni:

  • Porta 587 con STARTTLS è raccomandato
  • Migliore compatibilità con i firewall
  • Porta di invio SMTP standard

Per la massima compatibilità:

  • Entrambe le porte funzionano con EMailSender v4.0.0!
  • Scegli in base alle raccomandazioni del tuo provider di posta elettronica

Non per prestazioni e risorse

Tuttavia, ricorda che per usare STARTTLS avrai bisogno di più risorse in termini di RAM e Flash, quindi tienine conto.

Hardware

Qui per acquistare la mia selezione di 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

Qui per acquistare la mia selezione di 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

Qui per acquistare la mia selezione di 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

Per archiviare log e una grande quantità di dati, è utile utilizzare una scheda SD.

Anche per esp8266.

Qui per acquistare la mia selezione di moduli per schede SD AliExpress

Configurazione Software e Librerie

Installa le Librerie

IDE Arduino

  1. Apri l’IDE Arduino
  2. Vai su Sketch > Includi Libreria > Gestisci Librerie
  3. Cerca “EMailSender
  4. Fai clic su Installa

PlatformIO

Aggiungi al tuo platformio.ini:

lib_deps =
    xreef/EMailSender@^4.0.0

Installazione Manuale

  1. Scarica la libreria da GitHub
  2. Estrai nella cartella delle librerie di Arduino
  3. Riavvia l’IDE Arduino

Supporto Piattaforme

EMailSender v4.0.0 supporta una vasta gamma di piattaforme di microcontrollori:

PiattaformaWiFiEthernetSSL/TLSSTARTTLSStato
ESP32Supporto Completo
ESP8266Supporto Completo
Arduino MegaMemoria Limitata
Arduino UnoMemoria Limitata
Arduino SAMDSupporto Completo
STM32✅*Con Ethernet
Raspberry Pi Pico WSupporto Completo

* Necessita di una buona quantità di RAM

Interfacce di Rete

  • WiFi: ESP32, ESP8266, SAMD (WiFiNINA), Raspberry Pi Pico W
  • Ethernet W5100/W5200/W5500: Tutte le piattaforme
  • Ethernet ENC28J60: Tutte le piattaforme (con UIPEthernet)
  • Ethernet con SSL: Wrapper SSLClient per connessioni sicure

Guida Rapida per GMail

Inviamo la tua prima email con STARTTLS!

Ottieni la Password per le App di Gmail

Gmail non accetta più le password normali. Hai bisogno di una Password per le App:

  1. Vai al tuo Account Google
  2. Seleziona Sicurezza
  3. Abilita la Verifica in 2 passaggi (se non è già abilitata)
  4. Vai su Password per le apphttps://myaccount.google.com/apppasswords
  5. Genera una nuova password per “Posta” sul tuo dispositivo
  6. Copia la password di 16 caratteri (senza spazi)

Configura EMailSenderKey.h per STARTTLS

Apri EMailSenderKey.h e abilita il supporto a STARTTLS:

// Abilita il supporto STARTTLS per ESP32/ESP8266
#define EMAIL_ENABLE_INTERNAL_SSLCLIENT

// Abilita il debug (opzionale)
// #define EMAIL_SENDER_DEBUG
// #define DEBUG_PRINTER Serial

Esempio Base con STARTTLS

/*
 * 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
}

Output Atteso

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!

Ottimizzazione della Memoria, specialmente per ESP8266

Prima di tutto, non usare STARTTLS sulla porta 587, ma SSL/TLS implicito sulla porta 465

Controlla la Memoria Disponibile

Monitora sempre la memoria durante lo sviluppo:

void printMemoryStats() {
  Serial.println("\n=== Statistiche Memoria ===");
  Serial.printf("Heap Libero: %d byte\n", ESP.getFreeHeap());
  Serial.printf("Frammentazione Heap: %d%%\n", ESP.getHeapFragmentation());
  Serial.printf("Blocco Libero Massimo: %d byte\n", ESP.getMaxFreeBlockSize());
  Serial.printf("Dimensione Chip Flash: %d byte\n", ESP.getFlashChipSize());
  Serial.printf("Spazio Sketch Libero: %d byte\n", ESP.getFreeSketchSpace());
}

void setup() {
  Serial.begin(115200);
  delay(100);

  printMemoryStats();  // Controlla all'avvio
}

Usa PROGMEM per le Stringhe Statiche

// Sbagliato - usa RAM
const char* subject = "Allarme Temperatura da ESP8266";

// Giusto - usa Flash
const char subject[] PROGMEM = "Allarme Temperatura da ESP8266";

// Usa con:
String subjectStr = FPSTR(subject);

Riduci la Concatenazione di Stringhe

// Sbagliato - crea molte stringhe temporanee
String html = "<html><body>";
html += "<h1>Stato</h1>";
html += "<p>Temperatura: " + String(temp) + "</p>";
html += "</body></html>";

// Meglio - pre-calcola la dimensione
String html;
html.reserve(200);  // Riserva spazio in anticipo
html = "<html><body><h1>Stato</h1>";
html += "<p>Temperatura: ";
html += temp;
html += "</p></body></html>";

// Ottimo - usa la macro F()
String html = F("<html><body><h1>Stato</h1><p>Temperatura: ");
html += temp;
html += F("</p></body></html>");

Limita la Complessità dell’HTML

// HTML semplice e a basso consumo di memoria
void createSimpleHTML(float temp, float humidity) {
  String html = F("<!DOCTYPE html><html><body>");
  html += F("<h2>Rapporto Sensori</h2>");
  html += F("<p>Temp: ");
  html += String(temp, 1);
  html += F("C</p><p>Umidità: ");
  html += String(humidity, 1);
  html += F("%</p></body></html>");

  return html;
}

Usa lo Streaming per Dati Voluminosi

// Invece di costruire l'intera email in memoria
void sendStreamedData() {
  // Apri file
  File dataFile = LittleFS.open("/data.txt", "r");

  // Invia in blocchi
  EMailSender::FileDescriptior fileDesc;
  fileDesc.filename = "data.txt";
  fileDesc.url = "/data.txt";
  fileDesc.storageType = EMailSender::EMAIL_STORAGE_TYPE_LITTLE_FS;

  // EMailSender gestisce lo streaming automaticamente
}

Esempio base SSL/TLS

/*
 * 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
}


Il risultato diventa così.

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!

Esempi Avanzati

Email HTML con Stile

void sendHTMLEmail() {
  EMailSender::EMailMessage message;
  message.subject = "Rapporto di Stato ESP32";

  // Crea contenuto HTML
  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>Rapporto di Stato ESP32</h1></div>"
                "<div class='content'>"
                "<h2>Informazioni Dispositivo</h2>"
                "<p><strong>Indirizzo IP:</strong> " + WiFi.localIP().toString() + "</p>"
                "<p><strong>Segnale WiFi:</strong> " + String(WiFi.RSSI()) + " dBm</p>"
                "<p><strong>Heap Libero:</strong> " + String(ESP.getFreeHeap()) + " byte</p>"
                "<p><strong>Uptime:</strong> " + String(millis() / 1000) + " secondi</p>"
                "</div>"
                "<div class='footer'>Inviato dal Dispositivo ESP32</div>"
                "</body></html>";

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

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

  Serial.println(resp.status ? "Email inviata!" : "Fallito: " + resp.desc);
}

Sistema di Allarme con Sensore di Temperatura

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

// Sensore DHT (installa la libreria per sensori DHT)
#include <DHT.h>

#define DHT_PIN 4
#define DHT_TYPE DHT22

DHT dht(DHT_PIN, DHT_TYPE);

const char* ssid = "TUA_SSID";
const char* password = "TUA_PASSWORD";

EMailSender emailSend("allarme@gmail.com", "password_app",
                      "allarme@gmail.com", "Sensore ESP32",
                      "smtp.gmail.com", 587);

const float TEMP_ALTA = 30.0;    // Soglia temperatura alta
const float TEMP_BASSA = 15.0;     // Soglia temperatura bassa
const float UMIDITA_ALTA = 80.0; // Soglia umidità alta

unsigned long ultimoInvioEmail = 0;
const unsigned long INTERVALLO_EMAIL = 300000; // 5 minuti tra le email

void inviaAllarme(String tipoAllarme, float temp, float hum);

void setup() {
  Serial.begin(115200);
  dht.begin();

  // Connetti WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi Connesso!");

  emailSend.setEHLOCommand(true);
}

void loop() {
  float temperatura = dht.readTemperature();
  float umidita = dht.readHumidity();

  if (isnan(temperatura) || isnan(umidita)) {
    Serial.println("Lettura sensore fallita!");
    Serial.println("Imposto dati fittizi!");
    // Genera dati fittizi realistici che possono attivare allarmi
    // Temperatura: casuale tra 10°C e 35°C
    temperatura = 10.0 + (float)(rand() % 250) / 10.0;  // da 10.0 a 35.0
    // Umidità: casuale tra 40% e 90%
    umidita = 40.0 + (float)(rand() % 510) / 10.0;     // da 40.0 a 90.0
  }

  Serial.printf("Temp: %.1f°C, Umidità: %.1f%%\n", temperatura, umidita);

  // Controlla le soglie
  bool serveAllarme = false;
  String tipoAllarme = "";

  if (temperatura > TEMP_ALTA) {
    serveAllarme = true;
    tipoAllarme = "TEMPERATURA ALTA";
  } else if (temperatura < TEMP_BASSA) {
    serveAllarme = true;
    tipoAllarme = "TEMPERATURA BASSA";
  } else if (umidita > UMIDITA_ALTA) {
    serveAllarme = true;
    tipoAllarme = "UMIDITÀ ALTA";
  }

  // Invia allarme se necessario e non inviato di recente
  if (serveAllarme && (millis() - ultimoInvioEmail > INTERVALLO_EMAIL || ultimoInvioEmail == 0)) {
    Serial.println("Allarme Email!");
    inviaAllarme(tipoAllarme, temperatura, umidita);
    ultimoInvioEmail = millis();
  }

  // Leggi il sensore ogni 10 secondi
  delay(10000);
}

void inviaAllarme(String tipoAllarme, float temp, float hum) {
  Serial.println("Invio email di allarme...");

  EMailSender::EMailMessage message;
  message.subject = "⚠️ " + tipoAllarme + " ALLARME";

  String html = "<html><body style='font-family: Arial;'>"
                "<h2 style='color: #d32f2f;'>🚨 " + tipoAllarme + "</h2>"
                "<div style='background: #fff3e0; padding: 15px; border-left: 4px solid #ff9800;'>"
                "<p><strong>Temperatura:</strong> " + String(temp, 1) + "°C</p>"
                "<p><strong>Umidità:</strong> " + String(hum, 1) + "%</p>"
                "<p><strong>Ora:</strong> " + String(millis() / 1000) + " secondi dall'avvio</p>"
                "</div>"
                "<p style='color: #666; font-size: 12px; margin-top: 20px;'>Inviato dal Sistema di Monitoraggio ESP32</p>"
                "<p style='color: #999; font-size: 11px;'>Realizzato con la libreria EMailSender di 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("✅ Allarme inviato con successo!");
  } else {
    Serial.println("❌ Invio allarme fallito: " + resp.desc);
  }
}

Un sistema di monitoraggio basato su ESP32 che invia allarmi email automatici quando le soglie ambientali vengono superate.

Configurazione Hardware

#define DHT_PIN 4
#define DHT_TYPE DHT22

DHT dht(DHT_PIN, DHT_TYPE);

Sensore DHT22 collegato al GPIO 4 per le letture di temperatura e umidità.

Configurazione Email

EMailSender emailSend("tua@gmail.com", "password_app",
                      "tua@gmail.com", "Sensore ESP32",
                      "smtp.gmail.com", 587);

Configurazione SMTP di Gmail con autenticazione. Richiede una password per le app di Gmail (non la password normale).

Configurazione Soglie

const float TEMP_ALTA = 30.0;
const float TEMP_BASSA = 15.0;
const float UMIDITA_ALTA = 80.0;

const unsigned long INTERVALLO_EMAIL = 300000; // 5 minuti

Definisce le soglie di allarme e l’intervallo minimo tra le email per prevenire lo spam.

Lettura Sensore con Fallback

float temperatura = dht.readTemperature();
float umidita = dht.readHumidity();

if (isnan(temperatura) || isnan(umidita)) {
  // Genera dati fittizi realistici
  temperatura = 10.0 + (float)(rand() % 250) / 10.0;  // 10.0-35.0°C
  umidita = 40.0 + (float)(rand() % 510) / 10.0;     // 40.0-90.0%
}

Legge i dati del sensore ogni 10 secondi. Se la lettura fallisce, genera valori fittizi realistici per i test.

Logica di Allarme

if (temperatura > TEMP_ALTA) {
  tipoAllarme = "TEMPERATURA ALTA";
} else if (temperatura < TEMP_BASSA) {
  tipoAllarme = "TEMPERATURA BASSA";
} else if (umidita > UMIDITA_ALTA) {
  tipoAllarme = "UMIDITÀ ALTA";
}

if (serveAllarme && (millis() - ultimoInvioEmail > INTERVALLO_EMAIL || ultimoInvioEmail == 0)) {
  inviaAllarme(tipoAllarme, temperatura, umidita);
  ultimoInvioEmail = millis();
}

Controlla le soglie e invia un allarme immediatamente al primo superamento, poi rispetta un tempo di attesa di 5 minuti.

Formato Email HTML

EMailSender::EMailMessage message;
message.subject = "⚠️ " + tipoAllarme + " ALLARME";
message.mime = MIME_TEXT_HTML;

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

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

Invia un’email HTML con stile, con allarmi colorati e dati dei sensori formattati.

Se il sensore non funziona correttamente, il sistema genera automaticamente dati fittizi realistici per consentire test e sviluppo senza hardware funzionante.

Generatore di Rapporti Giornalieri

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

const char* ssid = "TUA_SSID";
const char* password = "TUA_PASSWORD";

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

// Programmazione rapporto (invia alle 08:00)
const int REPORT_HOUR = 17;
const int REPORT_MINUTE = 32;

bool reportSentToday = false;

void setup() {
  Serial.begin(115200);
  delay(1000); // Stabilizzazione iniziale

  // Connetti WiFi
  Serial.print("Connessione a 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("\nConnessione fallita!");
    ESP.restart();
    return;
  }

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

  delay(1000); // Attendi stabilizzazione WiFi

  // Configura l'ora con tentativi
  Serial.println("Sincronizzazione ora...");
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

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

  if (retry >= 10) {
    Serial.println("\nSincronizzazione NTP fallita!");
  } else {
    Serial.println("\nOra sincronizzata!");
    Serial.println(&timeinfo, "%Y-%m-%d %H:%M:%S");
  }

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

void sendDailyReport(struct tm timeinfo);

void loop() {
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    Serial.println("Ottenimento ora fallito");
    delay(60000);
    return;
  }

  // Stampa ora e stato correnti
  char timeStr[30];
  strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S", &timeinfo);
  Serial.print("Ora corrente: ");
  Serial.print(timeStr);
  Serial.print(" | Prossimo rapporto alle: ");
  Serial.print(REPORT_HOUR);
  Serial.print(":");
  Serial.print(REPORT_MINUTE < 10 ? "0" : "");
  Serial.println(REPORT_MINUTE);

  // Controlla se è ora di inviare il rapporto
  if (timeinfo.tm_hour == REPORT_HOUR &&
      timeinfo.tm_min == REPORT_MINUTE &&
      !reportSentToday) {

    sendDailyReport(timeinfo);
    reportSentToday = true;
  }

  // Resetta il flag a mezzanotte
  if (timeinfo.tm_hour == 0 && timeinfo.tm_min == 0) {
    reportSentToday = false;
    Serial.println("Flag rapporto resettato per nuovo giorno");
  }

  delay(60000); // Controlla ogni minuto
}

void sendDailyReport(struct tm timeinfo) {
  Serial.println("Generazione rapporto giornaliero...");

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

  EMailSender::EMailMessage message;
  message.subject = String("Rapporto Giornaliero - ") + dateStr;

  // Raccogli statistiche di sistema
  String html = "<html><body style='font-family: Arial;'>"
                "<h1>Rapporto Giornaliero ESP32</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;'>Metrica</th>"
                "<th style='padding: 10px; border: 1px solid #ddd;'>Valore</th>"
                "</tr>"
                "<tr><td style='padding: 8px; border: 1px solid #ddd;'>Uptime</td>"
                "<td style='padding: 8px; border: 1px solid #ddd;'>" +
                String(millis() / 86400000) + " giorni</td></tr>"
                "<tr><td style='padding: 8px; border: 1px solid #ddd;'>Heap Libero</td>"
                "<td style='padding: 8px; border: 1px solid #ddd;'>" +
                String(ESP.getFreeHeap()) + " byte</td></tr>"
                "<tr><td style='padding: 8px; border: 1px solid #ddd;'>Segnale WiFi</td>"
                "<td style='padding: 8px; border: 1px solid #ddd;'>" +
                String(WiFi.RSSI()) + " dBm</td></tr>"
                "<tr><td style='padding: 8px; border: 1px solid #ddd;'>Indirizzo IP</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;'>"
                "Rapporto automatico da 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("✅ Rapporto giornaliero inviato!");
  } else {
    Serial.println("❌ Invio rapporto fallito: " + resp.desc);
  }
}

Intestazioni e Dichiarazioni Globali

Questa sezione iniziale include le librerie necessarie e definisce costanti e variabili globali.

#include <WiFi.h>
#include <EMailSender.h>
#include <time.h>
  • #include <WiFi.h>: Include la libreria per la gestione della connessione Wi-Fi dell’ESP32.
  • #include <EMailSender.h>: Include una libreria personalizzata per l’invio di email.
  • #include <time.h>: Include la libreria per la gestione delle funzioni relative al tempo.
const char* ssid = "TUA_SSID";
const char* password = "TUA_PASSWORD";
  • ssid e password: Queste costanti contengono le credenziali (nome e password) per la tua rete Wi-Fi. Devi sostituire i valori segnaposto.
// Impostazioni NTP
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 0;
const int daylightOffset_sec = 3600;

  • Impostazioni NTP: Queste costanti configurano il Network Time Protocol (NTP), utilizzato per ottenere l’ora corretta da internet.
    • ntpServer: L’indirizzo del server NTP.
    • gmtOffset_sec: L’offset dal Greenwich Mean Time (GMT) in secondi.
    • daylightOffset_sec: L’offset per l’ora legale (3600 secondi = 1 ora).
// Programmazione rapporto (invia alle 08:00)
const int REPORT_HOUR = 17;
const int REPORT_MINUTE = 32;

bool reportSentToday = false;

  • REPORT_HOUR e REPORT_MINUTE: Queste costanti definiscono l’ora esatta (ora e minuto in formato 24 ore) in cui deve essere inviato il rapporto email giornaliero.
  • reportSentToday: Questo è un flag booleano utilizzato per garantire che il rapporto venga inviato solo una volta al giorno. Viene impostato su true dopo l’invio e resettato a false a mezzanotte.

Funzione sendDailyReport()

Questa funzione è responsabile della creazione del contenuto dell’email e del suo invio.

  • Genera Oggetto: Crea una riga di oggetto per l’email, come “Rapporto Giornaliero – 2025-10-09”.
  • Crea Corpo HTML: Costruisce una stringa formattata in HTML per il corpo dell’email. Ciò consente un rapporto visivamente più accattivante con un titolo, una data e una tabella.
  • Raccogli Dati di Sistema: La tabella nell’email contiene metriche chiave del sistema:
    • Uptime: Da quanto tempo l’ESP32 è in esecuzione.
    • Heap Libero: La quantità di memoria disponibile (RAM).
    • Segnale WiFi: La potenza del segnale Wi-Fi (RSSI).
    • Indirizzo IP: L’indirizzo IP corrente del dispositivo sulla rete.
  • Invia Email: Utilizza il metodo emailSend.send() della libreria per inviare l’email composta a un destinatario predefinito ("manager@example.com").
  • Registra Stato: Stampa un messaggio di successo o fallimento sul monitor seriale in base al risultato del tentativo di invio.

Allegati Multipli

Ricorda di usare FFAT (Per File di Grandi Dimensioni).

EMailSender::FileDescriptior files[3];

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

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

files[2].filename = "dati.txt";
files[2].url = "/dati.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("destinatario@example.com",
                                            message,
                                            attachments);

Allegati da SPIFFS/LittleFS/FFat (ESP32/ESP8266)

#include <SPIFFS.h>

// Inizializza 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;

// O usa LittleFS
// fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_LITTLE_FS;

// O usa FFAT
// fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_FFAT;

Allegati da Stream

Puoi allegare dati da qualsiasi sorgente Stream (ad es. dati generati, stream di rete o implementazioni personalizzate di Stream). Questo è utile quando vuoi inviare contenuto dinamico senza salvarlo prima su un file system.

// Esempio: Crea uno Stream da dati dinamici
Stream* myDataStream = ...; // La tua implementazione di Stream
size_t dataSize = 1024;     // Dimensione dei dati in byte

EMailSender::FileDescriptior fileDescriptor;
fileDescriptor.filename = "dati_sensore.csv";
fileDescriptor.mime = "text/csv";
fileDescriptor.encode64 = false;
fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_STREAM;
fileDescriptor.stream = myDataStream;      // Puntatore allo Stream
fileDescriptor.streamSize = dataSize;      // La dimensione è richiesta!

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

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

Allegati da Stringa (Raccomandato per Contenuto Dinamico)

Il modo più semplice per allegare contenuto generato dinamicamente. Passa semplicemente una Stringa direttamente – non c’è bisogno di file system o wrapper di Stream!

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

EMailSender::FileDescriptior fileDescriptor;
fileDescriptor.filename = "dati_sensore.json";
fileDescriptor.mime = "application/json";
fileDescriptor.encode64 = false;
fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_STRING;
fileDescriptor.content = jsonData;  // ✅ Assegna semplicemente la Stringa!

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

EMailSender::Response resp = emailSend.send("destinatario@example.com",
                                            message,
                                            attachments);
// Esempio 2: allegato CSV (compatibile con Excel)
String csvData = "Ora,Temperatura,Umidità\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 = "letture.csv";
fileDescriptor.mime = "text/csv";
fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_STRING;
fileDescriptor.content = csvData;  // ✅ Assegna semplicemente la Stringa!
// Esempio 3: allegati multipli da Stringa con diversi tipi MIME
String jsonData = "{\"device\":\"ESP32\",\"temp\":22.5,\"hum\":65.3}";
String csvData = "Sensore,Valore,Unità\nTemperatura,22.5,°C\nUmidità,65.3,%\n";
String xmlData = "<?xml version=\"1.0\"?><sensors><temp>22.5</temp><hum>65.3</hum></sensors>";
String txtData = "Dispositivo: ESP32\nTemperatura: 22.5°C\nUmidità: 65.3%\nStato: OK\n";

EMailSender::FileDescriptior files[4];

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

// Allegato CSV (compatibile con Excel)
files[1].filename = "dati.csv";
files[1].mime = "text/csv";
files[1].storageType = EMailSender::EMAIL_STORAGE_TYPE_STRING;
files[1].content = csvData;

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

// Allegato di testo
files[3].filename = "rapporto.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("destinatario@example.com",
                                            message,
                                            attachments);

Migliori Pratiche per Allegati da Stringa

  • Gestione della Memoria: Per contenuti di grandi dimensioni (>10KB), considera l’uso di Stream o archiviazione basata su file
  • Tipi MIME: Specifica sempre il tipo MIME corretto per una gestione adeguata da parte dei client di posta elettronica
  • Nomi dei File: Usa nomi di file descrittivi con estensioni appropriate (.json, .csv, .xml, .txt)
  • Validazione del Contenuto: Assicurati che il contenuto della tua Stringa sia valido (JSON valido, formato CSV corretto, ecc.)
  • Codifica Base64: Solitamente non necessaria per contenuti di testo; imposta encode64 = false

Risoluzione dei Problemi Comuni

  • “Errore: 220 -> …” o Timeout:
    • Verifica che il cavo Ethernet sia collegato correttamente.
    • Controlla che il server SMTP (smtp-relay.brevo.com) e la porta (587) siano corretti.
    • Assicurati che il firewall della tua rete non blocchi la porta 587.
  • “Errore: 535 -> Authentication failed”:
    • Le tue credenziali (Login o Chiave SMTP) sono errate. Controlla due volte la chiave SMTP dalla tua dashboard di Brevo.
    • Assicurati che il tuo indirizzo email mittente sia stato verificato in Brevo.
  • Inizializzazione della Scheda SD Fallita:
    • Controlla il cablaggio del tuo modulo per schede SD.
    • Assicurati che il SD_CS_PIN sia corretto e non entri in conflitto con il pin CS dello Shield Ethernet (solitamente il pin 10).

Specifiche della Libreria

Piattaforme Supportate

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

IMPORTANTE – Arduino Mega/Uno e SSL/TLS:

Arduino Mega e Uno NON supportano SSL/TLS a causa di gravi limitazioni di RAM:

  • Arduino Mega ha solo 8KB di RAM
  • Arduino Uno ha solo 2KB di RAM
  • BearSSL per SSL/TLS richiede almeno 24KB di RAM per i buffer di crittografia

Soluzioni alternative per Arduino Mega/Uno:

  1. Usa SMTP non sicuro (porta 25) – Funziona ma non è raccomandato
  2. Usa un relay SMTP locale – Configura un server locale che gestisca SSL
  3. Passa a ESP32/ESP8266 – Hanno più RAM e supporto nativo SSL/TLS
  4. Usa Arduino SAMD (MKR WiFi 1010) – Ha 32KB di RAM e supporta SSL/TLS

Gli esempi per Arduino Mega/Uno in questa libreria usano solo SMTP non sicuro!

Interfacce di Rete Supportate

  • WiFi (ESP32/ESP8266) – WiFiClient / WiFiClientSecure
  • WiFi (SAMD/MBED) – Libreria WiFiNINA
  • Ethernet W5100/W5200/W5500 – Libreria Ethernet standard
  • Ethernet ENC28J60 – Libreria UIPEthernet
  • Ethernet con SSL – Wrapper SSLClient per connessioni sicure

Sistemi di Archiviazione Supportati

Archiviazione Interna (Flash del Microcontrollore)

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

Archiviazione Esterna (Schede SD/microSD)

  • SD (Libreria SD standard)
  • SdFat (Versione 1.x per RP2040/ESP8266)
  • SdFat2 (Versione 2.x per piattaforme moderne)

Funzionalità della Libreria

Email HTML con Destinatari Multipli

EMailSender::EMailMessage message;
message.subject = "Test Email HTML";
message.message = "<h1>Ciao!</h1><p>Questa è un'email <b>HTML</b>.</p>";
message.mime = MIME_TEXT_HTML;  // Imposta il tipo MIME su HTML

// Destinatari multipli
const char* recipients[] = {
  "destinatario1@example.com",
  "destinatario2@example.com",
  "destinatario3@example.com"
};

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

Email con CC e BCC

// Array con indirizzi A, Cc e Ccn
const char* allRecipients[] = {
  "a@example.com",      // A (1)
  "cc@example.com",     // Cc (1)
  "ccn@example.com"     // Ccn (1)
};

// send(destinatari, numA, numCc, numCcn, messaggio)
EMailSender::Response resp = emailSend.send(allRecipients, 1, 1, 1, message);

Porta 587 (STARTTLS) – Raccomandato per Gmail

STARTTLS inizia con una connessione in chiaro e poi passa a una crittografata.

// Abilita SSLClient interno in EMailSenderKey.h
#define EMAIL_ENABLE_INTERNAL_SSLCLIENT

// Usa la porta 587
EMailSender emailSend("utente@gmail.com", "password_app",
                      "utente@gmail.com", "Nome Mittente",
                      "smtp.gmail.com", 587);

// Abilita EHLO (richiesto per STARTTLS)
emailSend.setEHLOCommand(true);

Porta 465 (SSL/TLS Implicito)

La connessione è crittografata fin dall’inizio.

// Usa WiFiClientSecure (ESP32/ESP8266)
EMailSender emailSend("utente@gmail.com", "password_app",
                      "utente@gmail.com", "Nome Mittente",
                      "smtp.gmail.com", 465);

// Nessuna configurazione aggiuntiva necessaria

Uso di SSLClient con Ethernet (Arduino/STM32)

Per schede senza supporto SSL nativo:

#define EMAIL_ENABLE_OPENSLAB_SSLCLIENT

// La libreria userà SSLClient basato su BearSSL
// per connessioni sicure su Ethernet

Funzionalità Avanzate

Metodi di Autenticazione Personalizzati

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

// Usa CRAM-MD5 (solo ESP32)
emailSend.setCramMD5Login(true);

// Disabilita l'autenticazione (open relay)
emailSend.setUseAuth(false);

Configurazione EHLO

// Usa EHLO invece di HELO (raccomandato per server moderni)
emailSend.setEHLOCommand(true);

// Imposta un identificatore personalizzato per HELO/EHLO
emailSend.setPublicIpDescriptor("miodispositivo");

Email con Allegati da Scheda SD

#include <SD.h>

// Inizializza la scheda SD
SD.begin(SD_CS_PIN);

// Prepara l'allegato
EMailSender::FileDescriptior fileDescriptor;
fileDescriptor.filename = "foto.jpg";
fileDescriptor.url = "/foto.jpg";  // Percorso sulla scheda SD
fileDescriptor.mime = MIME_IMAGE_JPG;
fileDescriptor.encode64 = true;  // Codifica in Base64
fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_SD;

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

// Invia email con allegato
EMailSender::Response resp = emailSend.send("destinatario@example.com",
                                            message,
                                            attachments);

Allegati Multipli

EMailSender::FileDescriptior files[3];

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

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

files[2].filename = "dati.txt";
files[2].url = "/dati.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("destinatario@example.com",
                                            message,
                                            attachments);

Allegati da SPIFFS/LittleFS/FFat (ESP32/ESP8266)

#include <SPIFFS.h>

// Inizializza 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;

// O usa LittleFS
// fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_LITTLE_FS;

// O usa FFAT
// fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_FFAT;

Tipo di archiviazione SPIFM

C’è anche il supporto per SPI Flash, ma è meglio fare riferimento al tutorial specifico.

// fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_SPIFM;

Tipo di archiviazione String o Stream

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

EMailSender::FileDescriptior files[1];

// Allegato JSON
files[0].filename = "data.json";
files[0].mime = "application/json";
files[0].storageType = EMailSender::EMAIL_STORAGE_TYPE_STRING;
files[0].content = jsonData;
Stream* myDataStream = ...; // La tua implementazione di Stream
size_t dataSize = 1024;     // Dimensione dei dati in byte

EMailSender::FileDescriptior fileDescriptor;
fileDescriptor.filename = "dati_sensore.csv";
fileDescriptor.mime = "text/csv";
fileDescriptor.encode64 = false;
fileDescriptor.storageType = EMailSender::EMAIL_STORAGE_TYPE_STREAM;
fileDescriptor.stream = myDataStream;      // Puntatore allo Stream
fileDescriptor.streamSize = dataSize;      // La dimensione è richiesta!

Tipi MIME Comuni per Allegati Stringa

Tipo di FileTipo MIMEUtilizzo
JSONapplication/jsonDati API, letture sensori
CSVtext/csvDati compatibili con Excel
XMLapplication/xmlFile di configurazione
Testotext/plainLog, report
HTMLtext/htmlDocumenti formattati
JavaScriptapplication/javascriptFile di codice

Confronto Tipi di Archiviazione

Tipo di ArchiviazioneIdeale PerComplessitàUso Memoria
EMAIL_STORAGE_TYPE_STRING📝 Contenuto testuale dinamico⭐ Molto FacileSolo RAM
EMAIL_STORAGE_TYPE_STREAM🔄 Sorgenti dati personalizzate⭐⭐ MedioStreaming RAM
EMAIL_STORAGE_TYPE_SD📁 File di grandi dimensioni⭐⭐ MedioScheda SD
EMAIL_STORAGE_TYPE_SPIFFS🔧 Piccoli file di configurazione⭐⭐ MedioFlash Interna
EMAIL_STORAGE_TYPE_LITTLE_FS📊 File medi (ESP32/ESP8266)⭐⭐ MedioFlash Interna
EMAIL_STORAGE_TYPE_FFAT📈 File grandi (solo ESP32)⭐⭐ MedioFlash Interna

Configurazione Gmail

Per usare Gmail, hai bisogno di una Password per le App:

  1. Abilita l’Autenticazione a 2 Fattori sul tuo account Google
  2. Vai su Password per le app di Google
  3. Genera una nuova password per le app
  4. Usa questa password di 16 caratteri nel tuo codice

Impostazioni Gmail:

  • Server SMTP: smtp.gmail.com
  • Porta: 587 (STARTTLS) o 465 (SSL/TLS)
  • Autenticazione: Richiesta

Su ESP32 ed ESP8266 puoi abilitare EMAIL_ENABLE_INTERNAL_SSLCLIENT nel file EMailSenderKey.h per usare STARTTLS sulla porta 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

Per la porta 465 e SSL/TLS, ESP32 ed ESP8266 non necessitano di librerie aggiuntive, ma per usarle con STM32 ed Ethernet (o altri dispositivi simili), puoi abilitare EMAIL_ENABLE_OPENSLAB_SSLCLIENT, un’implementazione leggera di 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

Riferimento API

Costruttore

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);

Metodi di Configurazione

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);  // Solo ESP32

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

Metodi di Invio

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

// Destinatari multipli (Solo A)
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});

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

// Destinatari multipli con Cc e Ccn
Response send(const char* to[], byte sizeOfTo, byte sizeOfCc, byte sizeOfCCn, EMailMessage &email, Attachments att = {0, 0});

Strutture Dati

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

// Descrittore File per Allegati
struct FileDescriptior {
    StorageType storageType = EMAIL_STORAGE_TYPE_SD;
    String mime;
    bool encode64 = false;
    String filename;
    String url;  // Percorso del file
};

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

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

Tipi di Archiviazione

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

Tipi MIME

Costanti predefinite per i tipi MIME:

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

File di Configurazione (EMailSenderKey.h)

La libreria usa un file di configurazione per abilitare/disabilitare le funzionalità:

// Abilita il supporto STARTTLS con SSLClient interno (ESP32/ESP8266)
#define EMAIL_ENABLE_INTERNAL_SSLCLIENT

// Abilita OpenSLab SSLClient per shield Ethernet (Arduino/STM32)
#define EMAIL_ENABLE_OPENSLAB_SSLCLIENT

// Abilita il supporto per gli allegati
#define ENABLE_ATTACHMENTS

// Abilita la gestione dell'header della data
#define MANAGE_DATE_HEADER

// Tipo di rete (rilevato automaticamente in base alla piattaforma)
// EMAIL_NETWORK_TYPE può essere:
// - NETWORK_ESP8266 (ESP8266 WiFi)
// - NETWORK_ESP32 (ESP32 WiFi)
// - NETWORK_W5100 (Ethernet W5100/W5200/W5500)
// - NETWORK_ENC28J60 (Ethernet ENC28J60)
// - NETWORK_WiFiNINA (SAMD/Arduino WiFiNINA)
// - ecc.

// Tipi di archiviazione
// INTERNAL_STORAGE può essere: STORAGE_SPIFFS, STORAGE_LITTLEFS, STORAGE_FFAT
// EXTERNAL_STORAGE può essere: STORAGE_SD, STORAGE_SDFAT2

Modalità Debug

Abilita il debug decommentando in EMailSenderKey.h:

#define EMAIL_SENDER_DEBUG
#define DEBUG_PRINTER Serial

Questo stamperà la comunicazione SMTP dettagliata sul Monitor Seriale.

Grazie

  1. ESP32: piedinatura, specifiche e configurazione dell’Arduino IDE
  2. ESP32: fileSystem integrato SPIFFS
  3. ESP32: gestire più seriali e logging per il debug
  4. ESP32 risparmio energetico pratico
    1. ESP32 risparmio energetico pratico: gestire WiFi e CPU
    2. ESP32 risparmio energetico pratico: modem e light sleep
    3. ESP32 risparmio energetico pratico: deep sleep e ibernazione
    4. ESP32 risparmio energetico pratico: preservare dati al riavvio, sveglia a tempo e tramite tocco
    5. ESP32 risparmio energetico pratico: sveglia esterna e da ULP
    6. ESP32 risparmio energetico pratico: sveglia da UART e GPIO
  5. ESP32: filesystem integrato LittleFS
  6. ESP32: filesystem integrato FFat (Fat/exFAT)
  7. ESP32-wroom-32
    1. ESP32-wroom-32: flash, piedinatura, specifiche e configurazione dell’Arduino IDE
  8. ESP32-CAM
    1. ESP32-CAM: piedinatura, specifiche e configurazione dell’Arduino IDE
    2. ESP32-CAM: upgrade CamerWebServer con gestione della luce flash
  9. ESP32: ethernet w5500 con chiamate standard (HTTP) e SSL (HTTPS)
  10. ESP32: ethernet enc28j60 con chiamate standard (HTTP) e SSL (HTTPS)
  11. Come usare la scheda SD con l’esp32
  12. esp32 e esp8266: file system FAT su memoria SPI flash esterna
  13. Gestione aggiornamenti firmware e OTA
    1. Gestione del firmware
      1. ESP32: flash del firmware binario compilato (.bin)
      2. ESP32: flash del firmware e filesystem (.bin) con strumenti grafici
    2. Aggiornamento OTA con Arduino IDE
      1. Aggiornamenti OTA su ESP32 con Arduino IDE: filesystem, firmware e password
    3. Aggiornamento OTA con browser web
      1. Aggiornamenti OTA su ESP32 tramite browser web: firmware, filesystem e autenticazione
      2. Aggiornamenti OTA su ESP32 tramite browser web: caricamento in HTTPS (SSL/TLS) con certificato autofirmato
      3. Aggiornamenti OTA su ESP32 tramite browser web: interfaccia web personalizzata
    4. Aggiornamenti automatici OTA da un server HTTP
      1. Aggiornamento automatico Firmware OTA dell’ESP32 dal server
      2. Aggiornamento automatico Firmware OTA dell’ESP32 dal server con controllo della versione
      3. Aggiornamento automatico Firmware OTA dell’ESP32 in HTTPS (SSL/TLS) con certificato autofirmato affidabile
    5. Aggiornamento del firmware non standard
      1. Aggiornamento firmware e filesystem ESP32 dalla scheda SD
      2. Aggiornamento firmware e filesystem ESP32 con client FTP
  14. Integrare LAN8720 con ESP32 per la connettività Ethernet con plain (HTTP) e SSL (HTTPS)
  15. Collegare l’EByte E70 (CC1310) ai dispositivi ESP32 c3/s3 ed un semplice sketch di esempio
  16. ESP32-C3: piedinatura, specifiche e configurazione dell’IDE Arduino
  17. Integrazione del modulo W5500 su ESP32 con Core 3: supporto nativo ai protocolli Ethernet con SSL e altre funzionalità
  18. Integrazione del modulo LAN8720 su ESP32 con Core 3: supporto nativo del protocollo Ethernet con SSL e altre funzionalità.
  19. Dallas DS18B20
  20. Guida all’I2C su ESP32: comunicazione con dispositivi eterogenei 5v 3.3v, gestione interfacce aggiuntive
  21. Display
  1. Come Inviare Email con Allegati da ESP32 e ESP8266 (Guida EMailSender 4.x.x e STARTTLS)

Spread the love

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *