Master ESP32 SMTP | Effortlessly Send Emails with Gmail!
ESP32 SMTP Integration with Gmail Email Sending Functionality is one of the Essential Skills in IoT Projects.
This complete tutorial will cover technical details including Wi-Fi connection, TLS encrypted connection to Gmail, SMTP command handshake, Base64 authentication, and more. It’s perfect for developers looking to enhance their ESP32 application capabilities.
Want to know how ESP32 sends Gmail emails via ESP32 SMTP?
This tutorial will walk you step-by-step from connecting to Wi-Fi to successfully sending your first email, thoroughly explaining Gmail SMTP authentication, TLS secure connection, and email sending flow!

Contents
What is SMTP?
SMTP (Simple Mail Transfer Protocol) is a standard Internet protocol used to send emails. Simply put, it’s the “postman” of email, responsible for transferring your mail from the sender to the recipient’s email server.
ESP32 is a Wi-Fi-capable microcontroller. We can use ESP32 with SMTP and Gmail or other mail services to make the ESP32 SMTP send emails automatically.
Development Environment
Before starting your programming, make sure to complete the following preparations:
- Install ESP-IDF (version 4.4 or higher): ESP-IDF is the official development framework for programming the ESP32, and it supports multiple operating systems such as Windows, macOS, and Linux.
- ESP32 Development Board: An ESP32 board is required.
Wi-Fi Connection
ESP32 SMTP needs to connect to a Wi-Fi network to access the Internet and connect to Gmail’s SMTP server.
// WiFi credentials - replace with your actual network information
#define WIFI_SSID "your_wifi_ssid"
#define WIFI_PASS "your_wifi_password"
// Function to initialize and connect to WiFi in station mode
void wifi_init_sta() {
// Create default WiFi station network interface
esp_netif_create_default_wifi_sta();
// Initialize WiFi with default configuration
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
// Configure WiFi station settings
wifi_config_t wifi_config = {
.sta = {
.ssid = WIFI_SSID, // Set SSID (network name)
.password = WIFI_PASS, // Set WiFi password
.threshold.authmode = WIFI_AUTH_WPA2_PSK, // Minimum security protocol
},
};
// Set WiFi to station mode (client mode)
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
// Apply the WiFi configuration
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
// Start the WiFi service
ESP_ERROR_CHECK(esp_wifi_start());
// Initiate connection to the configured WiFi network
ESP_ERROR_CHECK(esp_wifi_connect());
}
Wi-Fi Event Handling
We need to monitor Wi-Fi status changes, especially to start the email task after obtaining an IP address.
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
if (event_base == WIFI_EVENT)
{
switch (event_id)
{
case WIFI_EVENT_STA_START:
ESP_LOGI(TAG, "WiFi station started");
break;
case WIFI_EVENT_STA_CONNECTED:
ESP_LOGI(TAG, "WiFi connected successfully");
break;
case WIFI_EVENT_STA_DISCONNECTED:
ESP_LOGI(TAG, "WiFi disconnected");
break;
}
}
else if (event_base == IP_EVENT)
{
if (event_id == IP_EVENT_STA_GOT_IP)
{
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
ESP_LOGI(TAG, "Got IP: " IPSTR, IP2STR(&event->ip_info.ip));
// Create SMTP task once we have an IP address
xTaskCreate(smtp_task, "smtp_task", SMTP_TASK_STACK_SIZE, NULL, 5, NULL);
}
}
}
Establishing ESP32 SMTP Connection
We’ll use Gmail’s SMTP server for sending emails. The server address is smtp.gmail.com
, port 465
, using SSL/TLS encryption.
We need to use the esp_tls
library because ESP32 SMTP must support SSL/TLS.
Base64 Encoding Function
During the ESP32 SMTP authentication process, the email and password need to be Base64 encoded. Here’s a simple base64_encode
function for that.
char* base64_encode(const unsigned char *data, size_t input_length) {
const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
size_t output_length = 4 * ((input_length + 2) / 3);
char *encoded_data = malloc(output_length + 1);
if (encoded_data == NULL) return NULL;
for (size_t i = 0, j = 0; i < input_length;) {
uint32_t octet_a = i < input_length ? data[i++] : 0;
uint32_t octet_b = i < input_length ? data[i++] : 0;
uint32_t octet_c = i < input_length ? data[i++] : 0;
uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
encoded_data[j++] = base64_table[(triple >> 3 * 6) & 0x3F];
encoded_data[j++] = base64_table[(triple >> 2 * 6) & 0x3F];
encoded_data[j++] = base64_table[(triple >> 1 * 6) & 0x3F];
encoded_data[j++] = base64_table[(triple >> 0 * 6) & 0x3F];
}
for (size_t i = 0; i < (3 - input_length % 3) % 3; i++) {
encoded_data[output_length - 1 - i] = '=';
}
encoded_data[output_length] = '\0';
return encoded_data;
}
Email Sending Function
In the email sending process, we use SSL/TLS encryption to communicate with Gmail’s SMTP server and send mail via the ESP32 SMTP protocol.
void send_email() {
ESP_LOGI(TAG, "Starting SMTP connection, free heap: %d bytes", esp_get_free_heap_size());
// Configure TLS settings for secure SMTP connection
esp_tls_cfg_t tls_cfg = {
.timeout_ms = SMTP_TIMEOUT * 1000, // Connection timeout
.crt_bundle_attach = esp_crt_bundle_attach, // Use ESP32's certificate bundle
};
// Initialize TLS structure
esp_tls_t *tls = esp_tls_init();
if (!tls) {
ESP_LOGE(TAG, "Failed to initialize TLS");
return;
}
// Establish SSL connection to SMTP server (port 465 for SMTPS)
if (!esp_tls_conn_new_sync(SMTP_HOST, strlen(SMTP_HOST), SMTP_PORT, &tls_cfg, tls)) {
ESP_LOGE(TAG, "SSL connection failed");
esp_tls_conn_delete(tls);
return;
}
// SMTP protocol exchange
if (!smtp_exchange(tls, NULL, "220")) goto cleanup; // Wait for server greeting
if (!smtp_exchange(tls, "EHLO ESP32\r\n", "250")) goto cleanup; // Send EHLO
// Authentication process
char *auth_cmd = malloc(128);
if (!auth_cmd) goto cleanup;
// Initiate LOGIN authentication
if (!smtp_exchange(tls, "AUTH LOGIN\r\n", "334")) goto free_auth;
// Send base64-encoded username
char *encoded = base64_encode((const unsigned char *)SENDER_EMAIL, strlen(SENDER_EMAIL));
if (!encoded) goto free_auth;
snprintf(auth_cmd, 128, "%s\r\n", encoded);
free(encoded);
if (!smtp_exchange(tls, auth_cmd, "334")) goto free_auth;
// Send base64-encoded password
encoded = base64_encode((const unsigned char *)SENDER_PASSWORD, strlen(SENDER_PASSWORD));
if (!encoded) goto free_auth;
snprintf(auth_cmd, 128, "%s\r\n", encoded);
free(encoded);
if (!smtp_exchange(tls, auth_cmd, "235")) goto free_auth; // Expect authentication success
// Prepare email content
char *email_data = malloc(256);
if (!email_data) goto free_auth;
// Set sender
snprintf(email_data, 256, "MAIL FROM:<%s>\r\n", SENDER_EMAIL);
if (!smtp_exchange(tls, email_data, "250")) goto free_all;
// Set recipient
snprintf(email_data, 256, "RCPT TO:<%s>\r\n", RECIPIENT_EMAIL);
if (!smtp_exchange(tls, email_data, "250")) goto free_all;
// Begin data transmission
if (!smtp_exchange(tls, "DATA\r\n", "354")) goto free_all;
// Compose email headers and body
snprintf(email_data, 256,
"From: %s\r\nTo: %s\r\nSubject: ESP32 Test\r\n\r\n"
"Hello World!\r\n.\r\n", // The dot on a line by itself ends the message
SENDER_EMAIL, RECIPIENT_EMAIL);
// Send the actual email content
smtp_exchange(tls, email_data, "250"); // Expect 250 OK response
free_all:
free(email_data);
free_auth:
free(auth_cmd);
cleanup:
// Gracefully terminate the SMTP session
smtp_exchange(tls, "QUIT\r\n", NULL);
esp_tls_conn_delete(tls);
ESP_LOGI(TAG, "SMTP transaction completed");
}
Google App Password
Due to Google’s security restrictions on using account passwords for third-party apps (especially with 2-Step Verification enabled), you must use a Google App Password for this operation. This password is generated for a specific app/device and replaces your account password for authentication.
Step 1: Enable Google 2-Step Verification
- Log in to your Google account:
Visit the Google Account Page, and log in. - Enable 2-Step Verification:
Under “Security,” enable “2-Step Verification.”
Follow the prompts to complete setup — you’ll need to link your phone or another method.
Step 2: Generate an App Password
- After enabling 2FA, go to the “Security” section of your Google Account.
Find the “App Passwords” option. - Click “Generate App Password”.
- Choose “App” > Select “Other (Custom name)” and enter a name like “ESP32 SMTP”.
- Click Generate. Google will display a 16-character app password (e.g.,
abcd efgh ijkl mnop
). - Copy the App Password:
This is what you’ll use in the ESP32 code instead of your normal password.
Step 3: Use the App Password in Code
Replace the original Google account password in the code with the generated App Password:
#define SENDER_PASSWORD "your_app_password" // Use generated app-specific password for Gmail
Complete ESP32 SMTP Code
Here is the complete ESP32 SMTP code:
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "esp_tls.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#include "esp_crt_bundle.h"
// Configuration Section ============================================
#define WIFI_SSID "your_wifi_ssid" // Wi-Fi SSID
#define WIFI_PASS "your_wifi_password" // Wi-Fi password
#define SMTP_HOST "smtp.gmail.com" // Gmail SMTP server address
#define SMTP_PORT 465 // SMTP port (SSL)
#define SENDER_EMAIL "your_email@gmail.com" // Sender's Gmail address
#define SENDER_PASSWORD "your_app_password" // Gmail app password (generated in Google Account)
#define RECIPIENT_EMAIL "recipient_email@gmail.com" // Recipient's email address
#define SMTP_TIMEOUT 10 // SMTP timeout in seconds
#define SMTP_TASK_STACK_SIZE 8192 // Stack size for SMTP task
#define MAX_RETRIES 5 // Maximum retries for sending email
// ===============================================================
static const char *TAG = "SMTP_CLIENT";
static int s_retry_num = 0;
// Base64 encoding function
char* base64_encode(const unsigned char *data, size_t input_length) {
const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
size_t output_length = 4 * ((input_length + 2) / 3);
char *encoded_data = malloc(output_length + 1);
if (encoded_data == NULL) return NULL;
for (size_t i = 0, j = 0; i < input_length;) {
uint32_t octet_a = i < input_length ? data[i++] : 0;
uint32_t octet_b = i < input_length ? data[i++] : 0;
uint32_t octet_c = i < input_length ? data[i++] : 0;
uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
encoded_data[j++] = base64_table[(triple >> 3 * 6) & 0x3F];
encoded_data[j++] = base64_table[(triple >> 2 * 6) & 0x3F];
encoded_data[j++] = base64_table[(triple >> 1 * 6) & 0x3F];
encoded_data[j++] = base64_table[(triple >> 0 * 6) & 0x3F];
}
for (size_t i = 0; i < (3 - input_length % 3) % 3; i++) {
encoded_data[output_length - 1 - i] = '=';
}
encoded_data[output_length] = '\0';
return encoded_data;
}
// Function to handle SMTP communication with the server
bool smtp_exchange(esp_tls_t *tls, const char *send_str, const char *expect_resp) {
char *buf = malloc(256); // Allocate buffer for response
if (!buf) {
ESP_LOGE(TAG, "Failed to allocate buffer");
return false;
}
if (send_str != NULL) {
ESP_LOGI(TAG, "C: %s", send_str); // Log sent command
if (esp_tls_conn_write(tls, send_str, strlen(send_str)) < 0) {
free(buf);
return false;
}
}
int len = esp_tls_conn_read(tls, buf, 255);
if (len <= 0) {
free(buf);
return false;
}
buf[len] = '\0';
ESP_LOGI(TAG, "S: %.128s", buf); // Log server response (limited to 128 chars)
bool success = (expect_resp == NULL) || (strstr(buf, expect_resp) != NULL);
free(buf);
return success;
}
// Function to send email
void send_email() {
ESP_LOGI(TAG, "Starting SMTP connection, remaining heap: %d", esp_get_free_heap_size());
// Establish SSL connection
esp_tls_cfg_t tls_cfg = {
.timeout_ms = SMTP_TIMEOUT * 1000,
.crt_bundle_attach = esp_crt_bundle_attach,
};
esp_tls_t *tls = esp_tls_init();
if (!tls) {
ESP_LOGE(TAG, "Failed to initialize TLS");
return;
}
// Connect using SSL (port 465)
if (!esp_tls_conn_new_sync(SMTP_HOST, strlen(SMTP_HOST), SMTP_PORT, &tls_cfg, tls)) {
ESP_LOGE(TAG, "SSL connection failed");
esp_tls_conn_delete(tls);
return;
}
// SMTP protocol exchange
if (!smtp_exchange(tls, NULL, "220")) goto cleanup;
if (!smtp_exchange(tls, "EHLO ESP32\r\n", "250")) goto cleanup;
// Authentication process
char *auth_cmd = malloc(128);
if (!auth_cmd) goto cleanup;
if (!smtp_exchange(tls, "AUTH LOGIN\r\n", "334")) goto free_auth;
char *encoded = base64_encode((const unsigned char *)SENDER_EMAIL, strlen(SENDER_EMAIL));
if (!encoded) goto free_auth;
snprintf(auth_cmd, 128, "%s\r\n", encoded);
free(encoded);
if (!smtp_exchange(tls, auth_cmd, "334")) goto free_auth;
encoded = base64_encode((const unsigned char *)SENDER_PASSWORD, strlen(SENDER_PASSWORD));
if (!encoded) goto free_auth;
snprintf(auth_cmd, 128, "%s\r\n", encoded);
free(encoded);
if (!smtp_exchange(tls, auth_cmd, "235")) goto free_auth;
// Email content
char *email_data = malloc(256);
if (!email_data) goto free_auth;
snprintf(email_data, 256, "MAIL FROM:<%s>\r\n", SENDER_EMAIL);
if (!smtp_exchange(tls, email_data, "250")) goto free_all;
snprintf(email_data, 256, "RCPT TO:<%s>\r\n", RECIPIENT_EMAIL);
if (!smtp_exchange(tls, email_data, "250")) goto free_all;
if (!smtp_exchange(tls, "DATA\r\n", "354")) goto free_all;
snprintf(email_data, 256,
"From: %s\r\nTo: %s\r\nSubject: ESP32 Test\r\n\r\n"
"Hello World!\r\n.\r\n",
SENDER_EMAIL, RECIPIENT_EMAIL);
smtp_exchange(tls, email_data, "250");
free_all:
free(email_data);
free_auth:
free(auth_cmd);
cleanup:
smtp_exchange(tls, "QUIT\r\n", NULL);
esp_tls_conn_delete(tls);
ESP_LOGI(TAG, "SMTP process completed");
}
// SMTP task function
void smtp_task(void *pvParameters) {
ESP_LOGI(TAG, "SMTP task started");
// Send email
send_email();
vTaskDelete(NULL); // Task ends
}
// Wi-Fi event handler function
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
if (event_base == WIFI_EVENT)
{
switch (event_id)
{
case WIFI_EVENT_STA_START:
ESP_LOGI(TAG, "WiFi STA started");
break;
case WIFI_EVENT_STA_CONNECTED:
ESP_LOGI(TAG, "WiFi connected successfully");
s_retry_num = 0;
break;
case WIFI_EVENT_STA_DISCONNECTED:
if (s_retry_num < MAX_RETRIES)
{
ESP_LOGI(TAG, "Attempting to reconnect (%d/%d)", s_retry_num + 1, MAX_RETRIES);
esp_wifi_connect();
s_retry_num++;
}
else
{
ESP_LOGE(TAG, "Connection failed, exceeded maximum retry attempts");
}
break;
}
}
else if (event_base == IP_EVENT)
{
if (event_id == IP_EVENT_STA_GOT_IP)
{
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
ESP_LOGI(TAG, "Got IP: " IPSTR, IP2STR(&event->ip_info.ip));
// Create SMTP task
xTaskCreate(smtp_task, "smtp_task", SMTP_TASK_STACK_SIZE, NULL, 5, NULL);
}
}
}P_LOGI(TAG, "Got IP: " IPSTR, IP2STR(&event->ip_info.ip));
// Create SMTP task once IP is acquired
xTaskCreate(smtp_task, "smtp_task", SMTP_TASK_STACK_SIZE, NULL, 5, NULL);
}
}
}
// Wi-Fi initialization
void wifi_init_sta() {
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
// Register event handler
ESP_ERROR_CHECK(esp_event_handler_instance_register(
WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register(
IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, NULL));
wifi_config_t wifi_config = {
.sta = {
.ssid = WIFI_SSID,
.password = WIFI_PASS,
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_connect());
}
void app_main() {
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
wifi_init_sta();
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
Compilation and Flashing
After completing the code, you can use the commands provided by ESP-IDF to compile, flash, and monitor.
Check Your Inbox
After flashing and running the program, check your email inbox to verify that you have received the test email sent by your ESP32 SMTP device.
Conclusion
Through the complete implementation of this project, we have comprehensively mastered the core technologies for integrating ESP32 SMTP email services on the ESP32 platform. This ESP32 SMTP solution fully utilizes the chip’s Wi-Fi and hardware encryption acceleration advantages, establishing an encrypted connection with the ESP32 SMTP server via the TLS security protocol.
During implementation, we specifically optimized memory management for the ESP32 SMTP protocol stack, effectively addressing the challenges of sending large emails in resource-constrained environments through chunked processing techniques, while maintaining full ESP32 SMTP protocol compatibility.