DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
smtp.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file smtp.h
6 * @brief Outbound SMTP client (RFC 5321) - send a device email alert.
7 *
8 * A blocking one-shot: connect, greet, optional AUTH LOGIN, then MAIL FROM / RCPT TO /
9 * DATA a plain-text message and QUIT. It rides the shared outbound client transport
10 * (`det_client`), with implicit TLS (SMTPS, typically port 465) when the config sets
11 * `tls` and DETWS_ENABLE_TLS is on. Zero heap; every buffer is a compile-time size
12 * (`DETWS_SMTP_*`). Gated by DETWS_ENABLE_SMTP.
13 *
14 * The dialogue itself (smtp_run) is written against a send/recv seam, so the whole
15 * protocol exchange - greeting codes, AUTH, dot-stuffing, the terminating `.` - is
16 * unit-tested on the host with a scripted mock server, no lwIP or TLS required.
17 *
18 * "SMS fallback" needs no extra code: most mobile carriers accept an email-to-SMS
19 * gateway address (e.g. `5551234567@txt.example.net`) as the recipient.
20 *
21 * @author Douglas Quigg (dstroy0)
22 * @date 2026
23 */
24
25#ifndef DETERMINISTICESPASYNCWEBSERVER_SMTP_H
26#define DETERMINISTICESPASYNCWEBSERVER_SMTP_H
27
28#include <stddef.h>
29#include <stdint.h>
30
31/** @brief Result of an SMTP send. 0 is success; every failure is a distinct negative code. */
32enum class SmtpResult : int32_t
33{
34 SMTP_OK = 0,
35 SMTP_ERR_ARG = -1, ///< a required field (host / from / to) was null or empty
36 SMTP_ERR_CONNECT = -2, ///< could not open the transport (DNS / connect)
37 SMTP_ERR_TLS = -3, ///< the TLS handshake failed (SMTPS)
38 SMTP_ERR_IO = -4, ///< a send/recv failed or the reply timed out
39 SMTP_ERR_PROTOCOL = -5, ///< the server returned an unexpected reply code
40 SMTP_ERR_AUTH = -6, ///< AUTH was rejected (bad user/password)
41 SMTP_ERR_OVERFLOW = -7, ///< a command line or the message exceeded its fixed buffer
42};
43
44/**
45 * @brief Transport seam for smtp_run(): the engine sends and receives raw bytes only
46 * through these, so it can run against a real socket or a test mock.
47 *
48 * @return send: number of bytes written (must equal @p len), or <0 on error.
49 * @return recv: number of bytes read (>0), or <=0 on close / error / timeout.
50 */
51typedef int (*SmtpSendFn)(void *ctx, const uint8_t *data, size_t len);
52typedef int (*SmtpRecvFn)(void *ctx, uint8_t *buf, size_t cap);
53
54/** @brief Server address + credentials for one send. Addresses are bare (no angle brackets). */
56{
57 const char *host; ///< server hostname (also the TLS SNI name)
58 uint16_t port; ///< 25 / 587 / 465
59 bool tls; ///< true = implicit TLS on connect (SMTPS); false = plaintext
60 const char *user; ///< AUTH LOGIN username (null or empty => skip AUTH)
61 const char *pass; ///< AUTH LOGIN password
62 const char *from; ///< envelope sender + From: header address
63 const char *helo; ///< EHLO domain to announce (null => "esp32")
64};
65
66/** @brief One plain-text message. */
68{
69 const char *to; ///< single recipient address (envelope + To: header)
70 const char *subject; ///< Subject: header (null => empty)
71 const char *body; ///< plain-text UTF-8 body; LF or CRLF line ends, dot-stuffed for you
72};
73
74/**
75 * @brief Drive the full SMTP exchange over @p send / @p recv. Pure - no lwIP or TLS -
76 * so it is host-testable with a scripted transport.
77 * @return SmtpResult::SMTP_OK on a delivered message, else an ::SmtpResult error.
78 */
79SmtpResult smtp_run(const SmtpConfig *cfg, const SmtpMessage *msg, SmtpSendFn send, SmtpRecvFn recv, void *ctx);
80
81/**
82 * @brief Blocking one-shot send over the real transport (det_client, plus TLS when
83 * `cfg->tls`). Opens the connection, runs smtp_run(), and closes.
84 * @return SmtpResult::SMTP_OK or an ::SmtpResult error. On non-Arduino (host) builds there is no
85 * lwIP, so this returns SmtpResult::SMTP_ERR_CONNECT; use smtp_run() directly in tests.
86 */
88
89#endif // DETERMINISTICESPASYNCWEBSERVER_SMTP_H
SmtpResult smtp_send(const SmtpConfig *cfg, const SmtpMessage *msg)
Blocking one-shot send over the real transport (det_client, plus TLS when cfg->tls)....
int(* SmtpSendFn)(void *ctx, const uint8_t *data, size_t len)
Transport seam for smtp_run(): the engine sends and receives raw bytes only through these,...
Definition smtp.h:51
SmtpResult
Result of an SMTP send. 0 is success; every failure is a distinct negative code.
Definition smtp.h:33
@ SMTP_ERR_IO
a send/recv failed or the reply timed out
@ SMTP_ERR_ARG
a required field (host / from / to) was null or empty
@ SMTP_ERR_AUTH
AUTH was rejected (bad user/password)
@ SMTP_ERR_OVERFLOW
a command line or the message exceeded its fixed buffer
@ SMTP_ERR_TLS
the TLS handshake failed (SMTPS)
@ SMTP_ERR_PROTOCOL
the server returned an unexpected reply code
@ SMTP_ERR_CONNECT
could not open the transport (DNS / connect)
int(* SmtpRecvFn)(void *ctx, uint8_t *buf, size_t cap)
Definition smtp.h:52
SmtpResult smtp_run(const SmtpConfig *cfg, const SmtpMessage *msg, SmtpSendFn send, SmtpRecvFn recv, void *ctx)
Drive the full SMTP exchange over send / recv. Pure - no lwIP or TLS - so it is host-testable with a ...
Server address + credentials for one send. Addresses are bare (no angle brackets).
Definition smtp.h:56
const char * user
AUTH LOGIN username (null or empty => skip AUTH)
Definition smtp.h:60
bool tls
true = implicit TLS on connect (SMTPS); false = plaintext
Definition smtp.h:59
const char * pass
AUTH LOGIN password.
Definition smtp.h:61
const char * from
envelope sender + From: header address
Definition smtp.h:62
uint16_t port
25 / 587 / 465
Definition smtp.h:58
const char * host
server hostname (also the TLS SNI name)
Definition smtp.h:57
const char * helo
EHLO domain to announce (null => "esp32")
Definition smtp.h:63
One plain-text message.
Definition smtp.h:68
const char * body
plain-text UTF-8 body; LF or CRLF line ends, dot-stuffed for you
Definition smtp.h:71
const char * to
single recipient address (envelope + To: header)
Definition smtp.h:69
const char * subject
Subject: header (null => empty)
Definition smtp.h:70