ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
smtp.h File Reference

Outbound SMTP client (RFC 5321) - send a device email alert. More...

#include <stddef.h>
#include <stdint.h>

Go to the source code of this file.

Classes

struct  SmtpConfig
 Server address + credentials for one send. Addresses are bare (no angle brackets). More...
 
struct  SmtpMessage
 One plain-text message. More...
 

Typedefs

typedef 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, so it can run against a real socket or a test mock.
 
typedef int(* SmtpRecvFn) (void *ctx, uint8_t *buf, size_t cap)
 
typedef bool(* SmtpStartTlsFn) (void *ctx)
 Upgrade the live connection to TLS in place (RFC 3207), after the server's 220.
 

Enumerations

enum class  SmtpResult : int32_t {
  SMTP_OK = 0 , SMTP_ERR_ARG = -1 , SMTP_ERR_CONNECT = -2 , SMTP_ERR_TLS = -3 ,
  SMTP_ERR_IO = -4 , SMTP_ERR_PROTOCOL = -5 , SMTP_ERR_AUTH = -6 , SMTP_ERR_OVERFLOW = -7 ,
  SMTP_ERR_NO_STARTTLS = -8
}
 Result of an SMTP send. 0 is success; every failure is a distinct negative code. More...
 
enum class  SmtpSecurity : uint8_t { SMTP_PLAIN = 0 , SMTP_TLS = 1 , SMTP_STARTTLS = 2 }
 How the connection is secured. More...
 

Functions

SmtpResult smtp_run (const SmtpConfig *cfg, const SmtpMessage *msg, SmtpSendFn send, SmtpRecvFn recv, SmtpStartTlsFn starttls, void *ctx)
 Drive the full SMTP exchange over send / recv. Pure - no lwIP or TLS - so it is host-testable with a scripted transport.
 
SmtpResult smtp_send (const SmtpConfig *cfg, const SmtpMessage *msg)
 Blocking one-shot send over the real transport (pc_client, plus TLS when cfg->tls). Opens the connection, runs smtp_run(), and closes.
 

Detailed Description

Outbound SMTP client (RFC 5321) - send a device email alert.

A blocking one-shot: connect, greet, optional AUTH LOGIN, then MAIL FROM / RCPT TO / DATA a plain-text message and QUIT. It rides the shared outbound client transport (pc_client), with implicit TLS (SMTPS, typically port 465) when the config sets tls and PC_ENABLE_TLS is on. Zero heap; every buffer is a compile-time size (PC_SMTP_*). Gated by PC_ENABLE_SMTP.

The dialogue itself (smtp_run) is written against a send/recv seam, so the whole protocol exchange - greeting codes, AUTH, dot-stuffing, the terminating . - is unit-tested on the host with a scripted mock server, no lwIP or TLS required.

"SMS fallback" needs no extra code: most mobile carriers accept an email-to-SMS gateway address (e.g. 5551234567@txt.example.net) as the recipient.

Author
Douglas Quigg (dstroy0)
Date
2026

Definition in file smtp.h.

Typedef Documentation

◆ SmtpSendFn

typedef 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, so it can run against a real socket or a test mock.

Returns
send: number of bytes written (must equal len), or <0 on error.
recv: number of bytes read (>0), or <=0 on close / error / timeout.

Definition at line 60 of file smtp.h.

◆ SmtpRecvFn

typedef int(* SmtpRecvFn) (void *ctx, uint8_t *buf, size_t cap)

Definition at line 61 of file smtp.h.

◆ SmtpStartTlsFn

typedef bool(* SmtpStartTlsFn) (void *ctx)

Upgrade the live connection to TLS in place (RFC 3207), after the server's 220.

Called once, mid-dialogue. On success every later send/recv on the same ctx must be encrypted - the engine keeps using the same two function pointers, so the switch belongs to the transport, not to the caller.

Returns
true if the handshake completed.

Definition at line 71 of file smtp.h.

Enumeration Type Documentation

◆ SmtpResult

enum class SmtpResult : int32_t
strong

Result of an SMTP send. 0 is success; every failure is a distinct negative code.

Enumerator
SMTP_OK 
SMTP_ERR_ARG 

a required field (host / from / to) was null or empty

SMTP_ERR_CONNECT 

could not open the transport (DNS / connect)

SMTP_ERR_TLS 

the TLS handshake failed (SMTPS)

SMTP_ERR_IO 

a send/recv failed or the reply timed out

SMTP_ERR_PROTOCOL 

the server returned an unexpected reply code

SMTP_ERR_AUTH 

AUTH was rejected (bad user/password)

SMTP_ERR_OVERFLOW 

a command line or the message exceeded its fixed buffer

SMTP_ERR_NO_STARTTLS 

STARTTLS was required but the server did not advertise it.

Definition at line 32 of file smtp.h.

◆ SmtpSecurity

enum class SmtpSecurity : uint8_t
strong

How the connection is secured.

Enumerator
SMTP_PLAIN 

no TLS at all (port 25) - credentials and body travel in the clear.

SMTP_TLS 

implicit TLS from the first byte (SMTPS, port 465).

SMTP_STARTTLS 

connect in the clear, then upgrade in band (submission, port 587).

Definition at line 46 of file smtp.h.

Function Documentation

◆ smtp_run()

SmtpResult smtp_run ( const SmtpConfig cfg,
const SmtpMessage msg,
SmtpSendFn  send,
SmtpRecvFn  recv,
SmtpStartTlsFn  starttls,
void *  ctx 
)

Drive the full SMTP exchange over send / recv. Pure - no lwIP or TLS - so it is host-testable with a scripted transport.

With SmtpSecurity::SMTP_STARTTLS the engine issues STARTTLS after the first EHLO, calls starttls to upgrade the transport, and reissues EHLO (RFC 3207 sec 4.2 requires discarding the capabilities learned in the clear). If the server does not advertise STARTTLS it returns SmtpResult::SMTP_ERR_NO_STARTTLS before AUTH rather than continuing in the clear - a stripped STARTTLS must not silently downgrade into sending credentials in plaintext.

Returns
SmtpResult::SMTP_OK on a delivered message, else an SmtpResult error.

◆ smtp_send()

SmtpResult smtp_send ( const SmtpConfig cfg,
const SmtpMessage msg 
)

Blocking one-shot send over the real transport (pc_client, plus TLS when cfg->tls). Opens the connection, runs smtp_run(), and closes.

Returns
SmtpResult::SMTP_OK or an SmtpResult error. On non-Arduino (host) builds there is no lwIP, so this returns SmtpResult::SMTP_ERR_CONNECT; use smtp_run() directly in tests.