mailkite 0.13.0

Official MailKite SDK for Rust — inbound email → webhook, sending, templates, broadcasts, at-rest encryption, and webhook signature verification.
Documentation
# MailKite Rust SDK

The official [MailKite](https://mailkite.dev) SDK for Rust — inbound email → webhook,
sending, templates, contact lists, broadcasts, at-rest encryption, and webhook signature
verification. One low-level `request` plus one thin method per API endpoint; bodies and
responses are plain [`serde_json::Value`].

```toml
[dependencies]
mailkite = "0.13"
```

## Quickstart

```rust
use mailkite::Client;
use serde_json::json;

fn main() -> Result<(), mailkite::Error> {
    let mk = Client::new(std::env::var("MAILKITE_API_KEY").unwrap());

    let res = mk.send(json!({
        "from": "hello@app.mailkite.dev",
        "to": "ada@example.com",
        "subject": "Hi",
        "text": "It works.",
    }))?;
    println!("sent {}", res["id"]);
    Ok(())
}
```

## Authentication — API key or OAuth

The credential is always a Bearer token, so an **OAuth access token** works anywhere an API
key does. Rule of thumb: **server-to-server code → API key; anything that renders on a public
URL → OAuth** (so each user acts as themselves, not through a shared key).

```rust
use mailkite::Client;

// Server-to-server: a static API key (mk_live_…).
let mk = Client::new(std::env::var("MAILKITE_API_KEY").unwrap());

// OAuth: a static access token — same constructor, any Bearer credential.
let mk = Client::new(access_token);

// …or, because OAuth access tokens are short-lived, a get_token callback the SDK
// calls before each request so it always sends a fresh one (you refresh it):
let mk = Client::new_with_token(move || {
    Ok(current_session_access_token()) // -> Result<String, mailkite::Error>
});

// Point at a custom base URL (self-hosted / testing):
let mk = Client::new_with_base_url(api_key, "https://api.mailkite.dev");
```

Get an OAuth token from MailKite's authorization server (`mcp.mailkite.dev`, OAuth 2.1 +
PKCE, dynamic client registration).

## Receiving email (webhooks)

Verify the signature before trusting an inbound event — a local HMAC-SHA256 check, no network
call. Pass the **raw, unparsed** request body.

```rust
if mk.verify_webhook(signature_header, raw_body, webhook_secret) {
    // trusted — handle the event, then acknowledge:
    return mk.reply_ok(); // {"status":"ok"}  (also reply_spam / reply_drop / reply_block_sender)
}
```

## At-rest encryption

Hybrid RSA-OAEP (SHA-256) + AES-256-GCM. The envelope is byte-compatible with every other
MailKite SDK and MailKite's own WebCrypto, so you can encrypt in one language and decrypt in
another.

```rust
let envelope = mk.encrypt("secret", public_key_pem)?;   // -> compact JSON string
let plaintext = mk.decrypt(&envelope, private_key_pem)?;
```

## Uploading attachments

Get a secure, time-limited URL instead of base64-inlining large files on every send. Provide
the file one of four ways (`url`, `bytes`, `path`, or base64 `content`):

```rust
use mailkite::AttachmentUpload;

let up = mk.upload_attachment(AttachmentUpload {
    path: Some("invoice.pdf".into()),
    ..Default::default()
})?;
// then reference up["url"] as a send() attachment { filename, url }
```

## License

MIT