¿Te imaginas que tu ESP32 te avise por correo cuando se dispara un sensor, cuando la temperatura del invernadero pasa de cierto umbral o cuando la cámara detecta movimiento en la entrada? Mandar emails es una de las formas más prácticas de sacar datos de un microcontrolador hacia el mundo real, sin servidor propio ni app dedicada: el correo ya lo tienes y lo lees en cualquier dispositivo.
En este tutorial vas a aprender a enviar correos desde un ESP32 usando un servidor SMTP. Lo vamos a hacer en dos niveles: primero un email simple con cuerpo HTML o texto plano, y después un email con archivos adjuntos (una imagen y un archivo de texto) guardados en el sistema de archivos del ESP32. Al terminar vas a tener una base lista para integrar las notificaciones por correo en cualquiera de tus proyectos.
Qué es un servidor SMTP y por qué lo necesitas
SMTP son las siglas de Simple Mail Transfer Protocol, el estándar de Internet que se usa para transmitir correos. Tu ESP32 no envía el email directamente: se conecta a un servidor SMTP (el de Gmail, Outlook, etc.), se autentica con una cuenta y le entrega el mensaje para que ese servidor lo despache al destinatario. Es exactamente lo que hace tu cliente de correo del celular, solo que acá el "cliente" es la placa.
Para que el ESP32 hable SMTP vamos a apoyarnos en la librería ReadyMail de Mobizt, que permite enviar y recibir correos con o sin adjuntos vía SMTP e IMAP. En esta guía usamos solo la parte SMTP para enviar.
Qué necesitas
- Una placa ESP32 con conexión WiFi (cualquier DevKit con el chip ESP WROOM 32 sirve perfecto).
- El cable micro USB para alimentar y programar la placa.
- Arduino IDE instalado con el soporte de placas ESP32.
- Una cuenta de correo dedicada para el envío (más sobre esto abajo) y la cuenta donde quieres recibir las pruebas.
Fíjate que este proyecto no lleva protoboard ni cables de conexión: todo el trabajo es de software más la configuración de la cuenta de correo. El hardware se reduce a la placa y su cable.
Instala la librería ReadyMail
Antes de cargar cualquier código necesitas la librería. En Arduino IDE ve a Sketch > Include Library > Manage Libraries (Programa > Incluir Librería > Administrar Librerías), busca ReadyMail e instala la que es de Mobizt.

Como ves en la captura, la placa seleccionada en este ejemplo es una DOIT ESP32 DEVKIT V1, pero el código funciona igual en cualquier ESP32 con WiFi.
Crea una cuenta de envío y una contraseña de aplicación
Una recomendación importante de seguridad: no uses tu correo personal principal para enviar desde el ESP32. Si algo falla en tu código o por error mandas demasiadas solicitudes, te pueden bloquear o suspender temporalmente la cuenta. Crea una cuenta nueva (por ejemplo, una Gmail) solo para que el ESP32 envíe. El correo del destinatario sí puede ser tu cuenta personal sin problema.
Si vas a usar Gmail, hay un paso clave: necesitas una contraseña de aplicación (App Password). Esta es un código de 16 dígitos que le da permiso a un dispositivo "menos seguro" para acceder a tu cuenta de Google sin entregar tu contraseña real. Solo se puede generar en cuentas que tengan activada la verificación en dos pasos.
El flujo en Gmail es:
- Abre tu cuenta de Google y entra a Seguridad.
- Activa la verificación en dos pasos si aún no la tienes.
- Vuelve a buscar App Passwords (Contraseñas de aplicaciones) en el buscador de tu cuenta.
- Dale un nombre, por ejemplo ESP, y haz clic en Crear.

Google te mostrará una contraseña de 16 dígitos. Guárdala (aunque diga que no necesitas recordarla), porque es la que vas a poner en el código del ESP32. Si usas otro proveedor, busca cómo crear una contraseña de aplicación con una búsqueda del tipo "tu_proveedor + app password".
Datos del servidor SMTP de Gmail
Además de la cuenta, necesitas los datos del servidor SMTP de tu proveedor. Para Gmail son estos:
- Servidor SMTP: smtp.gmail.com
- Usuario SMTP: tu dirección Gmail completa
- Contraseña SMTP: tu contraseña de aplicación
- Puerto SMTP (TLS): 587
- Puerto SMTP (SSL): 465
- TLS/SSL requerido: sí
Si usas Outlook el servidor es smtp.office365.com y para Live o Hotmail es smtp.live.com, ambos por el puerto 587 con TLS/SSL. Para cualquier otro proveedor tendrás que buscar sus datos SMTP.
Código: enviar un correo con HTML o texto plano
El siguiente sketch envía un correo vía SMTP con cuerpo HTML o texto plano. Para demostrarlo, el ESP32 manda el email una sola vez al encender. Después la idea es que adaptes este código y lo integres en tus propios proyectos.
No lo subas todavía: primero tienes que insertar tus credenciales de red, el correo de envío, los datos del servidor SMTP, el destinatario y el mensaje.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at: https://RandomNerdTutorials.com/esp32-send-email-smtp-server-arduino-ide/
Based on the example provided by the ReadyMail library: https://github.com/mobizt/ReadyMail/
*/
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#define ENABLE_SMTP
#define ENABLE_DEBUG
#include <ReadyMail.h>
// REPLACE WITH YOUR NETWORK CREDENTIALS
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Sender SMTP settings (GMAIL)
// Change if using a different provider
#define SMTP_HOST "smtp.gmail.com"
#define SMTP_PORT 465
// Sender email, app password, and name
#define AUTHOR_EMAIL "your_email@gmail.com"
#define AUTHOR_APP_PASS "EMAIL_APP_PASSWORD"
#define AUTHOR_NAME "ESP32"
//Recipient's email
#define RECIPIENT_EMAIL "recipient_email@gmail.com"
#define RECIPIENT_NAME "RECIPIENT_NAME"
WiFiClientSecure ssl_client;
SMTPClient smtp(ssl_client);
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) delay(500);
ssl_client.setInsecure();
auto statusCallback = [](SMTPStatus status) {
Serial.println(status.text);
};
smtp.connect(SMTP_HOST, SMTP_PORT, statusCallback);
if (smtp.isConnected()) {
smtp.authenticate(AUTHOR_EMAIL, AUTHOR_APP_PASS, readymail_auth_password);
SMTPMessage msg;
msg.headers.add(rfc822_from, String(AUTHOR_NAME) + " <" + AUTHOR_EMAIL + ">");
msg.headers.add(rfc822_to, String(RECIPIENT_NAME) + " <" + RECIPIENT_EMAIL + ">");
msg.headers.add(rfc822_subject, "Hello from the ESP32");
//msg.text.body("This is a plain text message.");
msg.html.body("<html><body><h1>Hello!</h1></body></html>");
// Set NTP config time
/* For times east of the Prime Meridian use 0-12
For times west of the Prime Meridian add 12 to the offset.
Ex. American/Denver GMT would be -6. 6 + 12 = 18 */
const int gmtOffset_sec = 0; //offset time in seconds
const int daylightOffset_sec = 0; //daylight saving time offset in seconds
configTime(gmtOffset_sec, daylightOffset_sec, "pool.ntp.org");
// Set timestamp for the email
while (time(nullptr) < 100000) delay(100);
msg.timestamp = time(nullptr);
smtp.send(msg);
}
}
void loop() {
}
Puedes ver el código original sin formato en el repositorio de Random Nerd Tutorials en GitHub.
Cómo funciona el código
Primero incluimos las librerías necesarias y habilitamos el SMTP más el modo debug, que nos sirve para ver el estado del envío en el monitor serial:
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#define ENABLE_SMTP
#define ENABLE_DEBUG
#include <ReadyMail.h>
Después rellenas tus credenciales de red en ssid y password, y los datos del servidor SMTP. Si usas Gmail van así:
#define SMTP_HOST "smtp.gmail.com"
#define SMTP_PORT 465
Luego pones el correo y la contraseña de aplicación del remitente (ojo: la APP PASSWORD, no la contraseña normal del correo) en AUTHOR_EMAIL y AUTHOR_APP_PASS, y el correo del destinatario en RECIPIENT_EMAIL.
En el setup() se inicia el monitor serial, se conecta el ESP32 al WiFi y se crea una función statusCallback que imprime el estado de cada paso del envío. Tras conectarse al host y autenticarse, se arma un objeto SMTPMessage con las cabeceras (remitente, destinatario y asunto) y se define el cuerpo. Acá decides el formato: texto plano con msg.text.body() o HTML con msg.html.body(). Usa uno a la vez:
msg.text.body("This is a plain text message.");
//msg.html.body("<html><body><h1>Hello!</h1></body></html>");
Un detalle que mucha gente pasa por alto: antes de enviar, el código configura la hora vía un servidor NTP (pool.ntp.org) para ponerle una marca de tiempo válida al correo. Si el reloj del ESP32 está en cero, varios servidores rechazan o marcan el mensaje como sospechoso. Por eso el while (time(nullptr) < 100000) delay(100); espera a que la hora se sincronice antes de mandar. Finalmente, enviar es tan simple como smtp.send(msg);.
Prueba del envío
Sube el código al ESP32, abre el monitor serial a 115200 baudios y presiona el botón Reset de la placa. Si todo salió bien deberías ver una secuencia parecida a esta, terminando con el mensaje de éxito:

Revisa tu correo: deberías tener un email enviado por tu ESP32. Si dejaste activo el cuerpo HTML, se verá así en la bandeja de entrada:

Código: enviar correos con archivos adjuntos
En esta segunda parte vamos a mandar adjuntos en el correo: te mostramos cómo enviar un archivo .txt o una imagen. Esto es súper útil para, por ejemplo, despachar un .txt con las lecturas de un sensor de las últimas horas, o una foto capturada por una ESP32 CAM.
Para este caso los archivos a enviar deben estar guardados en el sistema de archivos del ESP32 (usaremos LittleFS).
Sube los archivos a LittleFS
Para adjuntar archivos, primero hay que subirlos al filesystem de la placa con el plugin ESP32 Filesystem Uploader de Arduino IDE. Crea un sketch nuevo y guárdalo; ve a Sketch > Show Sketch folder y dentro crea una carpeta llamada data. Mueve ahí una imagen y un archivo de texto.

Con el código por defecto, tus archivos deben llamarse image.png y text_file.txt (o modificas el código para usar otros nombres). Para subirlos, abre la paleta de comandos con Ctrl + Shift + P (Windows) o Cmd + Shift + P (macOS), busca el comando Upload LittleFS to Pico/ESP8266/ESP32 y ejecútalo. Si empiezan a aparecer muchos puntos en la consola, mantén presionado el botón BOOT de la placa para que la subida avance.
El código de los adjuntos
El siguiente código envía un correo con un archivo .txt y una imagen adjuntos. Antes de subirlo, recuerda insertar tus datos de envío y el correo del destinatario.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at: https://RandomNerdTutorials.com/esp32-send-email-smtp-server-arduino-ide/
*/
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <FS.h>
#include <LittleFS.h>
#define ENABLE_SMTP // Allows SMTP class and data
#define ENABLE_DEBUG // Allows debugging
#define ENABLE_FS // Allow filesystem integration
#define MY_FS LittleFS
#include <ReadyMail.h>
// REPLACE WITH YOUR NETWORK CREDENTIALS
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Sender SMTP settings (GMAIL)
// Change if using a different provider
#define SMTP_HOST "smtp.gmail.com"
#define SMTP_PORT 465
// Sender email, app password, and name
#define AUTHOR_EMAIL "your_email@gmail.com"
#define AUTHOR_APP_PASS "EMAIL_APP_PASSWORD"
#define AUTHOR_NAME "ESP32"
//Recipient's email
#define RECIPIENT_EMAIL "recipient_email@gmail.com"
#define RECIPIENT_NAME "RECIPIENT_NAME"
WiFiClientSecure ssl_client;
SMTPClient smtp(ssl_client);
// Create a file object
File myFile;
void fileCb(File &file, const char *filename, readymail_file_operating_mode mode) {
switch (mode) {
case readymail_file_mode_open_read:
myFile = MY_FS.open(filename, FILE_OPEN_MODE_READ);
break;
case readymail_file_mode_open_write:
myFile = MY_FS.open(filename, FILE_OPEN_MODE_WRITE);
break;
case readymail_file_mode_open_append:
myFile = MY_FS.open(filename, FILE_OPEN_MODE_APPEND);
break;
case readymail_file_mode_remove:
MY_FS.remove(filename);
break;
default:
break;
}
// This is required by library to get the file object
// that uses in its read/write processes.
file = myFile;
}
void initLittleFS() {
if (!MY_FS.begin(true)){
Serial.println("LittleFS Mount Failed");
return;
}
}
// For more information, see http://bit.ly/474niML
void smtpCb(SMTPStatus status){
if (status.progress.available)
ReadyMail.printf("ReadyMail[smtp][%d] Uploading file %s, %d %% completed\n", status.state,
status.progress.filename.c_str(), status.progress.value);
else
ReadyMail.printf("ReadyMail[smtp][%d]%s\n", status.state, status.text.c_str());
}
void addFileAttachment(SMTPMessage &msg, const String &filename, const String &mime, const String &name, FileCallback cb, const String &filepath, const String &encoding = "", const String &cid = "") {
Attachment attachment;
attachment.filename = filename;
attachment.mime = mime;
attachment.name = name;
// The inline content disposition.
// Should be matched the image src's cid in html body
attachment.content_id = cid;
attachment.attach_file.callback = cb;
attachment.attach_file.path = filepath;
// Specify only when content is already encoded.
attachment.content_encoding = encoding;
msg.attachments.add(attachment, cid.length() > 0 ? attach_type_inline : attach_type_attachment);
}
void setup() {
Serial.begin(115200);
Serial.println();
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) delay(500);
initLittleFS();
// If server SSL certificate verification was ignored for this ESP32 WiFiClientSecure.
// To verify root CA or server SSL cerificate,
// please consult your SSL client documentation.
ssl_client.setInsecure();
smtp.connect(SMTP_HOST, SMTP_PORT, smtpCb);
if (!smtp.isConnected())
return;
smtp.authenticate(AUTHOR_EMAIL, AUTHOR_APP_PASS, readymail_auth_password);
if (!smtp.isAuthenticated())
return;
SMTPMessage msg;
msg.headers.add(rfc822_from, String(AUTHOR_NAME) + " <" + AUTHOR_EMAIL + ">");
msg.headers.add(rfc822_to, String(RECIPIENT_NAME) + " <" + RECIPIENT_EMAIL + ">");
msg.headers.add(rfc822_subject, "ESP32 Attachments");
String bodyText = "Hello! See attachments";
msg.text.body(bodyText);
msg.html.body("<html><body><div style=\"color:#cc0066;\">" + bodyText + "</div></body></html>");
// Set NTP config time
/* For times east of the Prime Meridian use 0-12
For times west of the Prime Meridian add 12 to the offset.
Ex. American/Denver GMT would be -6. 6 + 12 = 18 */
const int gmtOffset_sec = 0; //offset time in seconds
const int daylightOffset_sec = 0; //daylight saving time offset in seconds
configTime(gmtOffset_sec, daylightOffset_sec, "pool.ntp.org");
// Set timestamp for the email
while (time(nullptr) < 100000) delay(100);
msg.timestamp = time(nullptr);
addFileAttachment(msg, "image.png", "image/png", "image.png", fileCb, "/image.png");
addFileAttachment(msg, "text_file.txt", "text/plain", "text_file.txt", fileCb, "/text_file.txt");
Serial.print("Sending email");
smtp.send(msg);
}
void loop(){
}
Este sketch es muy parecido al anterior, así que veamos solo lo nuevo. Se incluyen las librerías FS y LittleFS para manejar archivos, y se habilita la integración con el filesystem definiendo el tipo (SPIFFS, LittleFS o SD):
#define ENABLE_FS // Allow filesystem integration
#define MY_FS LittleFS
La función addFileAttachment() concentra todos los pasos para crear y agregar un adjunto al mensaje. Estos son los parámetros que recibe:
SMTPMessage &msg: el objeto del mensaje donde se agrega el adjunto.const String &filename: el nombre de archivo que verá el destinatario.const String &mime: el tipo MIME del archivo (por ejemploimage/png,text/plain).const String &name: el nombre visible del adjunto.FileCallback cb: la función callback que se llama al agregar el adjunto.const String &filepath: la ruta del archivo en el filesystem.const String &encoding: déjalo vacío, salvo que el contenido ya venga codificado.const String &cid: el content ID para adjuntos inline (para incrustar imágenes dentro del HTML del correo).
Para mandar la imagen y el texto que subiste, en el setup() se llama así:
addFileAttachment(msg, "image.png", "image/png", "image.png", fileCb, "/image.png");
addFileAttachment(msg, "text_file.txt", "text/plain", "text_file.txt", fileCb, "/text_file.txt");
Y al final se envía igual que antes con smtp.send(msg);.
Prueba de los adjuntos
Sube el código, abre el monitor serial a 115200 baudios y presiona el botón EN/RESET. Si todo va bien verás el progreso de la subida de cada archivo en la consola. Después revisa el correo del destinatario: deberías tener un email nuevo con los dos adjuntos.

Variantes y mejoras
Una vez que tienes el envío funcionando, el código del setup() es solo el punto de partida. Algunas ideas para llevarlo más allá:
- Notificaciones por sensor en vez de al encender. Mueve la lógica de envío a una función que llames cuando se cumpla una condición (por ejemplo, lectura de un DHT22 sobre 30 grados). Así el correo deja de mandarse una vez al boot y pasa a ser una alerta real.
- Reporte diario con deep sleep. Combina este proyecto con el modo deep sleep del ESP32: la placa duerme la mayor parte del tiempo, despierta cada cierto intervalo, arma un
.txtcon los datos acumulados y lo manda como adjunto. Ideal para estaciones a batería. - Foto por correo con la ESP32 CAM. Si usas una ESP32 CAM, guarda la captura en el filesystem y adjúntala con el mismo
addFileAttachment(). Tendrás un detector que te envía la foto del evento directo al mail. - Cuerpo HTML con estilo. El método
msg.html.body()acepta HTML completo, así que puedes armar correos con tabla de lecturas, colores y enlaces, en vez de texto plano.
Personalización para Chile
En Chile puedes conseguir el hardware de este proyecto en MechatronicStore. Como es un tutorial de puro software más la nube, la lista es corta y honesta:
- ESP32 con WiFi y Bluetooth (ESP WROOM 32) (wc_id 3688): $7.990 CLP. Es la placa DevKit que usa el tutorial; trae WiFi integrado, que es todo lo que necesitas para hablar con el servidor SMTP.
- Cable micro USB para cargar y transferir datos (wc_id 8992): $2.190 CLP. Alimenta y programa la placa desde el computador.
El resto de lo necesario no es hardware de tienda: el Arduino IDE es gratuito, la cuenta de correo de envío la creas en Gmail u otro proveedor, y los archivos image.png y text_file.txt los pones tú. Si en otro tutorial ves una placa "Adafruit Feather" o similar, el ESP32 DevKit cumple la misma función para enviar correos a una fracción del precio.
Recursos
- Tutorial original (inglés): ESP32 Send Emails using an SMTP Server: HTML, Text, and Attachments (Arduino IDE), por Rui Santos y Sara Santos en Random Nerd Tutorials.
- Librería ReadyMail (Mobizt): github.com/mobizt/ReadyMail
- Código del ejemplo simple: ESP32_Send_Email_Simple.ino
Versión chilena basada en el tutorial de Random Nerd Tutorials, con componentes en stock local en MechatronicStore.




