Skip to content
copidaPublic

About

An ultra-lightweight, high-performance, and RAM-optimized SMTP client library for Arduino (ESP32 )

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

13 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SmtpMini

Minimal SMTP client for ESP32 (Arduino core) with support for:

  • plain text or HTML email bodies
  • attachments from RAM
  • attachments from filesystem (SD, LittleFS, or any fs::FS compatible filesystem)
  • streaming Base64 encoding to keep memory usage low
  • SMTPS (port 465) as the default mode
  • STARTTLS (port 587) as an optional mode using ESP_SSLClient
  • optional server-certificate verification using a CA certificate
  • optional Date: header for better compatibility with SMTP servers expecting complete email headers

The goal of the library is to stay small, simple, and practical for Arduino projects that need to send emails without bringing in heavy dependencies.


Features

  • SMTP over a secure client
  • secure email sending with TLS/SSL
  • optional server-certificate verification with a CA certificate
  • plain text or HTML body
  • multiple attachments
  • multi-recipient email : "recipient1@gmail.com;recipient2@outlook.com"
  • attachments from RAM and/or filesystem in the same email
  • streaming Base64 encoding
  • support for:
    • implicit TLS / SMTPS on port 465 as the default mode
    • STARTTLS on port 587 when enabled
  • optional Date: header for better compatibility with stricter SMTP servers
  • simple API:
    • begin()
    • setSmtpServer()
    • setSMTPtime()
    • sendEmail()
    • getLastError()
  • optional debug logging via SMTP_MINI_DEBUG

Requirements

  • ESP32 board with Arduino core
  • Wi-Fi connection
  • SMTP server supporting either:
    • SMTPS on port 465
    • STARTTLS on port 587
  • For Gmail, an app password is required

Important

  • Default mode is SMTPS on port 465 using WiFiClientSecure.
  • STARTTLS on port 587 is available only when SMTP_USE_STARTTLS is enabled, using ESP_SSLClient.
  • Pass a CA certificate to setSmtpServer() to verify the SMTP server certificate; without one, the connection is encrypted but the server certificate is not verified.
  • The library can optionally include the Date: header to improve compatibility with stricter SMTP servers.
  • The destination email address is sent as a single RCPT TO unless MULTIRCPT is enabled.
  • QUIT is sent as a best-effort SMTP close command, but a successful message is already considered delivered once the server accepts it after DATA.

Installation

Copy the library folder into your Arduino libraries/ directory, or add it as a local library in PlatformIO.


Quick start

Default mode: SMTPS on port 465

#include <WiFi.h>
#include <SD.h>
#include <SmtpMini.h>

//Single library instance: TCP/TLS clients are managed internally
SmtpMini mailer;

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

  WiFi.begin("YOUR_WIFI", "YOUR_WIFI_PASSWORD");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWi-Fi connected");

  if (!SD.begin()) {
    Serial.println("SD init failed");
  }


  mailer.begin("sender@gmail.com", "your_app_password", &SD);
//smtp.gmail.com and port 465 are the defaults... optional
  //mailer.setSmtpServer("smtp.gmail.com", 465);

  SMTPAttachment attachments[1] = {
    { "/report.csv" }
  };

  bool ok = mailer.sendEmail(
    "recipient@example.com",
    "SmtpMini test",
    "Hello! This is a test email.",
    false,
    attachments,
    1
  );

  if (ok) {
    Serial.println("Email sent successfully");
  } else {
    Serial.printf("SMTP error: %d\n", mailer.getLastError());
  }
}

void loop() {}

STARTTLS on port 587

This example is only valid if SMTP_USE_STARTTLS is enabled in SmtpMini.h.

#include <WiFi.h>
#include <SmtpMini.h>
SmtpMini mailer;

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

  WiFi.begin("YOUR_WIFI", "YOUR_WIFI_PASSWORD");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }

  mailer.begin("sender@gmail.com", "your_app_password");
//Set port 587 for automatic STARTTLS communication
  mailer.setSmtpServer("smtp.gmail.com", 587);

  bool ok = mailer.sendEmail(
    "recipient@example.com",
    "STARTTLS test",
    "Hello from STARTTLS!",
    false
  );

  if (ok) Serial.println("Email sent successfully");
  else    Serial.printf("SMTP error: %d\n", mailer.getLastError());
}

void loop() {}

Verify the SMTP server certificate

By default, the connection is encrypted but the server certificate is not verified. To verify the server, provide its trusted CA certificate in PEM format as the third argument to setSmtpServer(). This works with SMTPS and with STARTTLS when SMTP_USE_STARTTLS is enabled.

// Replace this placeholder with the complete CA certificate (PEM) that
// validates the certificate presented by your SMTP server.
static const char smtpRootCA[] = R"CERT(
-----BEGIN CERTIFICATE-----
... paste the CA certificate here ...
-----END CERTIFICATE-----
)CERT";

mailer.setSmtpServer("smtp.gmail.com", 465, smtpRootCA);

Keep the certificate string available for the lifetime of the mailer; setSmtpServer() stores its pointer rather than copying the certificate. If the third argument is omitted or nullptr, the library uses setInsecure(), so TLS encryption remains enabled but the server identity is not verified. Use the CA certificate for your SMTP server, not a client certificate.

MULTI RECIPIENT

Support for Multiple Recipients and Friendly Names

You can specify multiple recipients by separating them with a semicolon (;).

The library automatically parses the string, handles the individual routing commands to the SMTP server (RCPT TO), and generates a standards-compliant To: header.

1. Standard Example with Multiple Recipients

To send the same email to multiple addresses, simply pass them as a single string, separated by semicolons:

bool ok = mailer.sendEmail(
  "recipient1@example.com;recipient2@gmail.com;recipient3@outlook.com",
  "Test with multiple recipients",
  "Hello from SmtpMini!",
  false
);

2. Support for Friendly Names (Name + Email)

You can optionally include a friendly name (alias) for the primary recipient, allowing a human-readable name to be displayed instead of just the email address.

bool ok = mailer.sendEmail(
  "IT Manager;mario.rossi@gmail.com;recipient2@gmail.com;plain-email@example.com",
  "Test with friendly names",
  "Hello from SmtpMini with human-readable headers!",
  false
);

API

begin()

bool begin(const char* email, const char* appPassword, fs::FS* fileSystem = nullptr);

Sets sender credentials and, optionally, the filesystem used for file attachments.

mailer.begin(mail, pass, &SD);
mailer.begin(mail, pass, &LittleFS);
mailer.begin(mail, pass);          // RAM attachments only

The strings are not copied: they must stay valid for the whole program.

setSmtpServer()

void setSmtpServer(const char* host, uint16_t port, const char* certCA = nullptr);

Overrides the SMTP host and port. Pass the server's trusted CA certificate in PEM format as certCA to verify its certificate. The host and certificate strings are not copied; they must remain valid while the mailer uses them. If certCA is omitted or nullptr, certificate verification is disabled.

setSMTPtime()

void setSMTPtime(const char* timestr);

Sets the optional Date: header value used by the message builder.

Example:

configTime(3600, 3600, "pool.ntp.org");

struct tm t;
static char dateBuf[40];
if (getLocalTime(&t)) {
  //static char dateBuf[40]; ..no!
  strftime(dateBuf, sizeof(dateBuf), "%a, %d %b %Y %H:%M:%S %z", &t);
  mailer.setSMTPtime(dateBuf);
}

If setSMTPtime() is never called, no Date: header is sent.

sendEmail()

bool sendEmail(const char* mailboxes, const char* subject, const char* body,
               bool isHtml = false,
               SMTPAttachment* attachments = nullptr,
               size_t attachmentCount = 0);
Parameter Description
mailboxes Recipient (a single RCPT TO)
subject Subject
body Message body
isHtml true = text/html, false = text/plain (UTF-8)
attachments Array of SMTPAttachment (or nullptr)
attachmentCount Number of elements in the array

Returns true if the server accepted the message (250 after DATA). If an attachment could not be fully encoded, the message is still sent and getLastError() returns -4.

Input filtering: CR, LF and " are removed from mailboxes, the email address, subject and attachment names, and values are truncated (address 64, subject 80, attachment name 50 characters) to prevent header injection. The body is not filtered for these characters.

getLastError()

int getLastError() const;

Returns the last error code. On success, it returns 0.


Attachments

struct SMTPAttachment {
  const char* nomeFile = nullptr;       // name (RAM) or path (filesystem)
  const void* bufferRAM = nullptr;    // leave nullptr for filesystem files
  size_t lunghezzaRAM = 0;            // leave 0 for filesystem files
};

From the filesystem

SMTPAttachment a("/logs/data.csv");       // requires a filesystem in begin()

From RAM

const char text[] = "Generated in RAM";

SMTPAttachment b("log.txt", text, strlen(text));   // name shown in the email

String strtext = "stringa in formato testo\n";
strtext += "seconda riga della stringa";

SMTPAttachment c("testo.txt", strtext.c_str(), , strtext.length()); 

Rules

  • If bufferRAM != nullptr and lunghezzaRAM > 0 → sent from RAM.
  • Otherwise, if nomeFile is not empty → read from the filesystem passed to begin().
  • The name shown in the email is the last path component (/logs/data.csv → data.csv).
  • nomeFile holds at most 63 characters.
  • If the file cannot be opened or is empty, it is skipped.
  • All attachments are sent as application/octet-stream.
  • RAM and filesystem attachments can be mixed in the same email.

Error codes

getLastError() returns:

Code Meaning
0 No error recorded / successful send
-1 Timeout or connection closed while waiting for a server reply
-2 TCP/TLS connection to the server failed
-3 Body transmission failed
-4 Message sent, but an attachment was incomplete or skipped (no name, read/send error)
other SMTP code received instead of the expected one (for example 535, 554)

Common SMTP codes:

Code Meaning
220 Service ready / ready to start TLS
221 Service closing transmission channel
235 Authentication succeeded
250 Command accepted
334 Authentication challenge
354 Start mail input
421 Service not available, closing connection
454 STARTTLS temporarily unavailable
530 TLS activation or authentication required
535 Authentication failed
550 Mailbox unavailable / invalid recipient

Note: the code is stored whenever the reply does not match the expected one, including server greeting, authentication, MAIL FROM, RCPT TO, DATA, STARTTLS, and the final message acceptance after DATA. Enable SMTP_MINI_DEBUG to inspect the server dialogue.

Common BearSSL codes:

Code BearSSL Meaning
0 BR_ERR_OK No error (unexpected if the 'if' condition failed; check the timeout)
26 BR_ERR_BAD_VERSION The server requires a TLS version that is not supported (e.g., TLS 1.3)
32 BR_ERR_BAD_CERT_SIGN The certificate signature is invalid, or the CA chain is incorrect
60 BR_ERR_X509_EXPIRED The server certificate has expired (or the ESP's clock is not synchronized via NTP
62 BR_ERR_X509_NOT_TRUSTED The root CA certificate is not trusted or is missing from your code

Client lifecycle

  • QUIT is sent as a best-effort SMTP close command.
  • A message is considered successfully sent once the server accepts it after DATA with 250.

Debug

Uncomment in SmtpMini.h:

#define SMTP_MINI_DEBUG

When enabled, the library prints the SMTP dialogue (C: / S: lines), the authentication result and the attachment progress. Connection and SMTP error messages are printed on Serial regardless of this option.


Security note

TLS encrypts the connection. The library verifies the SMTP server certificate only when a CA certificate is supplied to setSmtpServer(); otherwise, it calls setInsecure(), so the server's identity is not verified. Certificate verification is available in both SMTPS and STARTTLS modes.


Limitations

  • Authentication: AUTH LOGIN only
  • Single body part (text or HTML)
  • ESP32 only

Example

See examples/testsmail.ino: Wi-Fi, SD card, simple email and mixed SD/RAM attachments.


License

MIT

About

An ultra-lightweight, high-performance, and RAM-optimized SMTP client library for Arduino (ESP32 )

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages