daaki-smtp 0.2.0

An async SMTP client library
Documentation
# daaki-smtp

A Rust SMTP/LMTP client built with tokio & rustls.

## Highlights

- **SMTP and LMTP** — support for RFC 5321 and RFC 2033.
- **Pipelining** — batches commands automatically when the server advertises it.
- **CHUNKING/BINARYMIME** — send large or binary messages via BDAT without dot-stuffing.
- **Async with explicit timeouts** — built on tokio. Every operation takes a `Duration`.
- **TLS by default** — rustls-based TLS with implicit TLS (port 465) and STARTTLS.
- **Typed API** — validated newtypes (`ReversePath`, `ForwardPath`, `Domain`, `Mailbox`) and typed results (`SendResult`, `LmtpSendResult`) catch errors at construction time.
- **Zero unsafe code** — enforced by `#![deny(unsafe_code)]` crate-wide.
- **Optional serde** — enable the `serde` feature for `Serialize`/`Deserialize` on all public types.

## Quick Start

```toml
[dependencies]
daaki-smtp = "0.2"
```

Connect, authenticate, and send a message:

```rust,no_run
use daaki_smtp::{SmtpConnection, TlsMode, ReversePath, ForwardPath};
use std::time::Duration;

#[tokio::main]
async fn main() -> daaki_smtp::Result<()> {
    let timeout = Duration::from_secs(30);

    let conn = SmtpConnection::connect(
        "smtp.example.com", 465, TlsMode::Implicit, timeout,
    ).await?;
    conn.auth_plain("user@example.com", "password", timeout).await?;

    let message = b"From: user@example.com\r\n\
                    To: recipient@example.com\r\n\
                    Subject: Hello\r\n\
                    \r\n\
                    Hello, world!\r\n";

    let from = ReversePath::new("user@example.com")?;
    let to = vec![ForwardPath::new("recipient@example.com")?];
    conn.send(&from, &to, message, timeout).await?;
    conn.quit(timeout).await?;
    Ok(())
}
```

### LMTP

Connect to an LMTP server for local delivery. Returns per-recipient results:

```rust,no_run
# use daaki_smtp::{SmtpConnection, TlsMode, ReversePath, ForwardPath};
# use std::time::Duration;
# async fn example() -> daaki_smtp::Result<()> {
let timeout = Duration::from_secs(30);

let conn = SmtpConnection::connect_lmtp(
    "localhost", 24, TlsMode::None, timeout,
).await?;

let from = ReversePath::new("user@example.com")?;
let to = vec![ForwardPath::new("local@example.com")?];
let result = conn.send_lmtp(&from, &to, b"Subject: Hi\r\n\r\nHello\r\n", None, timeout).await?;

for r in &result.results {
    println!("{}: {}", r.recipient, r.response.text());
}
# Ok(())
# }
```

## Supported Extensions

| Category | Extensions | RFCs |
|----------|-----------|------|
| **Content encoding** | 8BITMIME, CHUNKING, BINARYMIME | RFC 1652, 3030 |
| **Transport** | PIPELINING, SIZE, STARTTLS, Implicit TLS | RFC 1854, 1870, 3207, 8314 |
| **Auth** | AUTH (PLAIN, LOGIN, OAUTHBEARER, XOAUTH2) | RFC 4954, 4616, 7628 |
| **Delivery** | DSN (NOTIFY, ORCPT, RET, ENVID), REQUIRETLS, DELIVERBY, FUTURERELEASE, MT-PRIORITY | RFC 3461, 8689, 2852, 4865, 6758 |
| **Status & addressing** | ENHANCEDSTATUSCODES, SMTPUTF8, VRFY, EXPN, NO-SOLICITING | RFC 2034, 6531, 5321, 3865 |

Compatibility note: some servers advertise a legacy, non-standard `SASL-IR`
EHLO keyword. `daaki-smtp` preserves it for introspection, but RFC 4954
Section 4 already allows SMTP AUTH initial responses without a separate
standard extension.

## License

The contents of this package are licensed under the terms of the MIT license.