# Send email from Rust

Send email from any Rust app with Groundmail. For most apps, use the [Rust SDK](https://docs.groundmail.dev/sdks/rust). This guide covers the alternatives: SMTP with **lettre**, or the REST API with **reqwest**.

| | SMTP (lettre) | REST API (reqwest) |
|---|---|---|
| Best for | Existing code that already sends over SMTP | New code, retries, delivery status |
| Credential | SMTP credential (`gmsmtp_…`) | API key (`gm_…`) |
| Response | `250` from the server | Message ID (`msg_…`) and status, structured errors |
| Idempotency | `X-Groundmail-Idempotency-Key` header | `Idempotency-Key` header |

Both use the same verified domains, suppressions, limits and webhooks.

---

## Before you start

1. [Add and verify your sending domain](https://docs.groundmail.dev/domains). To test before DNS is set up, send from `noreply@mail.groundmail.dev` to your own account email.
2. Create the credential you need at [app.groundmail.dev](https://app.groundmail.dev): an **SMTP credential** or an **API key**.
3. Keep it out of source control. Read it from an environment variable.

---

## Send with SMTP and lettre

[lettre](https://github.com/lettre/lettre) is Rust's most widely used email library.

```bash
cargo add lettre@0.11 --no-default-features --features builder,hostname,smtp-transport,tokio1,tokio1-rustls-tls,ring,rustls-native-certs
cargo add tokio --features macros,rt-multi-thread
```

| Setting | Value |
|---------|-------|
| Host | `smtp.groundmail.dev` |
| Port | `587` |
| Security | STARTTLS |
| Username | `groundmail` |
| Password | Your SMTP credential (`gmsmtp_…`) |

```rust
use lettre::message::{header::ContentType, Mailbox, MultiPart, SinglePart};
use lettre::transport::smtp::authentication::Credentials;
use lettre::{AsyncSmtpTransport, AsyncTransport, Message, Tokio1Executor};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let from: Mailbox = "Acme <billing@yourdomain.com>".parse()?;
    let to: Mailbox = "user@example.com".parse()?;

    let email = Message::builder()
        .from(from)
        .to(to)
        .subject("Your receipt")
        .multipart(
            MultiPart::alternative()
                .singlepart(SinglePart::builder().header(ContentType::TEXT_PLAIN).body("Thanks for your order.".to_owned()))
                .singlepart(SinglePart::builder().header(ContentType::TEXT_HTML).body("<p>Thanks for your order.</p>".to_owned())),
        )?;

    let password = std::env::var("GROUNDMAIL_SMTP_PASSWORD")?;
    let mailer = AsyncSmtpTransport::<Tokio1Executor>::starttls_relay("smtp.groundmail.dev")?
        .port(587)
        .credentials(Credentials::new("groundmail".to_owned(), password))
        .build();

    mailer.send(email).await?;
    Ok(())
}
```

To send many messages, reuse one transport: it keeps a pool of connections.

---

## Send with reqwest and the REST API

```bash
cargo add reqwest --no-default-features --features json,rustls-tls
cargo add serde_json
cargo add tokio --features macros,rt-multi-thread
```

```rust
use serde_json::{json, Value};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api_key = std::env::var("GROUNDMAIL_API_KEY")?;

    let response = reqwest::Client::new()
        .post("https://api.groundmail.dev/emails")
        .bearer_auth(api_key)
        .header("Idempotency-Key", "receipt-order-1042")
        .json(&json!({
            "from": "Acme <billing@yourdomain.com>",
            "to": "user@example.com",
            "subject": "Your receipt",
            "html": "<p>Thanks for your order.</p>",
        }))
        .send()
        .await?;

    let status = response.status();
    let body: Value = response.json().await?;
    if !status.is_success() {
        return Err(format!("{status}: {}", body["error"]["message"]).into());
    }

    println!("{} {}", body["id"], body["status"]);
    Ok(())
}
```

Retrying with the same `Idempotency-Key` returns the first result instead of sending twice. See the [Send email API](https://docs.groundmail.dev/api-explorer) for every field.

---

## Next steps

- [Webhooks](https://docs.groundmail.dev/webhooks): get delivery and bounce events.
- [SMTP](https://docs.groundmail.dev/smtp): headers, limits and errors.
- [Domains](https://docs.groundmail.dev/domains): verify your sending domain.
