# 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