# SMTP `deft/smtp` is an event-driven SMTP client over the native `net/*` namespace, plus RFC 5322/MIME message construction. Every command is an `@async` function to `await`. It is a nested package inside stdext and mounts as its own top-level package.
import "deft/smtp" as smtp
import "deft/smtp/message" as mail
## Client | Def | Signature | Description | |---|---|---| | `connect` | `{| host port opts |}` | Connect (implicit TLS by default); `%SmtpClient` or `%Err` | | `send` | `{| client message opts |}` | Deliver a message; `%{ accepted rejected reply log }` | | `quit` / `disconnect` | `{| client |}` | Close the session | | `state` | `{| client |}` | `:connected / :ready / :authenticated / :closed` | | `ehlo` | `{| client |}` | EHLO (falls back to HELO) | | `authenticate` | `{| client user pass auth |}` | AUTH `:plain` or `:login` | | `mail-from` / `rcpt-to` | `{| client address opts |}` | Envelope commands | | `has-extension?` / `capabilities` / `extension-args` | `{| … |}` | EHLO capability inspection | | `noop` / `rset` / `verify` | `{| … |}` | Session maintenance | `connect` options: `:tls` (default `true` for port 465), `:starttls` (port 587, upgrade before AUTH), `:user` / `:pass`, `:auth` (`:plain` / `:login`), `:timeout` (ms, default 30000). One command is in flight per connection; replies are queued in arrival order.
def cli [await [smtp/connect "smtp.example.com" 465
                %{ :user "me" :pass "secret" }]]
def r [await [smtp/send $cli %{
    :from "me@example.com"
    :to   @{ "you@example.com" }
    :subject "hello"
    :text "world" }]]
echo $r~accepted $r~rejected $r~reply~code
[await [smtp/quit $cli]]
Rejected recipients carry `%{ address code message enhanced }` (RFC 3463 enhanced codes like `5.1.1`). ## Message Construction `deft/smtp/message` builds a 7-bit-clean RFC 5322 message with CRLF line endings, safe for SMTP DATA:
set raw [mail/build %{
    :from "me@example.com"
    :to   @{ "you@example.com" }
    :subject "hello"
    :text "plain"
    :html "<p>html</p>"
    :attachments @{ %{ :filename "a.bin"
                       :content-type "application/octet-stream"
                       :data $bytes } } }]
[mail/dot-stuff $raw]     # before the "." terminator
Addresses accept a string, a comma-separated string, a vector, or `%{ :name :address }`. Encoded words handle non-ASCII headers; bodies get base64 attachments under `multipart/mixed`, text+html under `multipart/alternative`. `deft/smtp/parser` is the incremental reply framer (`drain`, reply predicates `ok?`/`transient?`/`permanent?`, extension parsing); `deft/imap/message` is the decoder counterpart. ## See Also - IMAP — the receiving side - Mail app help — the client built on these - Network — the `net/*` primitives underneath