LettermintLettermint
  • Knowledge base
  • Community
  • Changelog
  • Support
  • Documentation
  • Sending API
  • Team API
  • MCP server
Get started
Send email
    Send with
      SDKs
        Node.jsPHPPythonGoJava.NETElixirRust
      Frameworks
    SMTP
    Email activitySchedulingTest emailsTLSIdempotencySuppressionsTagsInline imagesData retentionSending limits
    Tracking
Receive email
Manage
Resources
SDKs

Rust

Use the official Lettermint Rust SDK to send email from a Rust application. The SDK also supports the Team API and webhook signature verification. See SDKs and integrations for other packages.

Requirements

  • Rust 1.98 or newer
  • Tokio or another async runtime that is compatible with reqwest
  • A Project API token

Install the SDK

Add the SDK and Tokio to Cargo.toml:

TOMLCode
[dependencies] lettermint = "1" tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

Run cargo build to install the dependencies. The package is also available on crates.io, and its API reference is on docs.rs.

Send your first email

Store your Project API token in LETTERMINT_TOKEN. Then, create an email client and send a message:

Code
use lettermint::Lettermint; #[tokio::main] async fn main() -> lettermint::Result<()> { let email = Lettermint::email(std::env::var("LETTERMINT_TOKEN").unwrap())?; let response = email .email() .from("John Doe <john@yourdomain.com>") .to("recipient@example.com") .subject("Hello from Lettermint") .text("This is a test email sent with the Lettermint Rust SDK.") .html("<p>This is a test email sent with the Lettermint Rust SDK.</p>") .send() .await?; println!("Email sent with ID: {}", response.message_id); Ok(()) }

API acceptance does not confirm delivery. Use webhooks to receive delivery and bounce events.

Add email options

Each call to email.email() starts a new message. Options from one message do not stay in the next message.

Recipients and reply-to addresses

Call to, cc, bcc, or reply_to more than once to add multiple addresses:

Code
let response = email .email() .from("support@yourdomain.com") .to("customer@example.com") .to("account-owner@example.com") .cc("manager@yourdomain.com") .bcc("archive@yourdomain.com") .reply_to("help@yourdomain.com") .subject("Your support request") .text("We received your support request.") .send() .await?;

Metadata and headers

Use metadata to add application data to webhook payloads. Metadata does not add headers to the email:

Code
let response = email .email() .from("orders@yourdomain.com") .to("customer@example.com") .subject("Order confirmation") .text("Your order is confirmed.") .metadata("order_id", "12345") .metadata("customer_id", "cust_789") .header("X-Priority", "1") .send() .await?;

Tags

Use typed name and value tags to organize messages for filtering and analytics:

Code
use lettermint::types::MessageTag; let response = email .email() .from("notifications@yourdomain.com") .to("user@example.com") .subject("Your account is ready") .text("You can now sign in.") .tags([ MessageTag::new("campaign", "welcome")?, MessageTag::new("customer", "new")?, ]) .send() .await?;

You can add up to 20 typed tags. The tag method remains available for one legacy tag. You can add up to 19 typed tags when you also use a legacy tag. See Tags for the value rules.

Route and tracking settings

Select a route and control open and click tracking for the message:

Code
use lettermint::email::EmailSettings; use lettermint::types::TlsPolicy; let response = email .email() .from("notifications@yourdomain.com") .to("user@example.com") .subject("Security alert") .text("A new device signed in to your account.") .route("transactional") .settings(EmailSettings { track_opens: Some(false), track_clicks: Some(false), tls: Some(TlsPolicy::Enforced), }) .send() .await?;

See open tracking, click tracking, and TLS delivery for the related behavior.

Attachments and inline images

Attachment content must be Base64-encoded. Add the base64 crate if your application does not already encode files:

TOMLCode
[dependencies] base64 = "0.22"
Code
use base64::{Engine as _, engine::general_purpose::STANDARD}; let invoice = std::fs::read("invoice.pdf").expect("read invoice.pdf"); let response = email .email() .from("billing@yourdomain.com") .to("customer@example.com") .subject("Your invoice") .text("Your invoice is attached.") .attach_with_options( "invoice.pdf", STANDARD.encode(invoice), None, Some("application/pdf".to_string()), ) .send() .await?;

For an inline image, set the content ID and use the same value in the HTML cid: URL:

Code
let response = email .email() .from("welcome@yourdomain.com") .to("customer@example.com") .subject("Welcome") .html(r#"<p>Welcome!</p><img src="cid:logo" alt="Company logo">"#) .attach_with_options( "logo.png", encoded_logo, Some("logo".to_string()), Some("image/png".to_string()), ) .send() .await?;

See Attachments and inline images for size and file type limits.

Idempotency

Use the same idempotency key when you retry the same logical email:

Code
let response = email .email() .from("orders@yourdomain.com") .to("customer@example.com") .subject("Order confirmation") .text("Your order is confirmed.") .idempotency_key("order-12345-confirmation") .send() .await?;

See Idempotency for key rules and the retention period.

Schedule an email

Use an RFC 3339 UTC timestamp to schedule an email:

Code
let response = email .email() .from("events@yourdomain.com") .to("attendee@example.com") .subject("Event reminder") .text("Your event starts tomorrow.") .scheduled_at("2026-10-01T09:00:00Z") .send() .await?;

See Email scheduling for scheduling limits and cancellation behavior.

Handle errors

Match the SDK error variants to handle API, validation, network, and decoding failures:

Code
use lettermint::{Error, Lettermint}; async fn send_email() -> lettermint::Result<()> { let email = Lettermint::email(std::env::var("LETTERMINT_TOKEN").unwrap())?; match email .email() .from("sender@yourdomain.com") .to("recipient@example.com") .subject("Test") .text("Hello!") .send() .await { Ok(response) => println!("Status: {:?}", response.status), Err(Error::Validation { error_type, body }) => { eprintln!("Validation error: {error_type}, details: {body:?}"); } Err(Error::Http { status, message, .. }) => { eprintln!("API error {status}: {message}"); } Err(Error::Request(error)) => eprintln!("Request failed: {error}"), Err(error) => eprintln!("Send failed: {error}"), } Ok(()) }

The SDK removes the active token from API error data before it returns the error.

Use the Team API

Create a separate client with a Team API token. Store the token in LETTERMINT_TEAM_TOKEN:

Code
use lettermint::Lettermint; #[tokio::main] async fn main() -> lettermint::Result<()> { let api = Lettermint::api(std::env::var("LETTERMINT_TEAM_TOKEN").unwrap())?; let domains = api.domains().list(&[("page[size]", "10")]).await?; for domain in domains.data { println!("{}", domain.domain); } Ok(()) }

The email client sends the Project API token in X-Lettermint-Token. The Team API client uses bearer authentication. Do not use a Project API token for Team API operations.

Verify webhook signatures

Pass the raw request body and the exact Lettermint signature header to the verifier:

Code
use lettermint::Webhook; fn verify_webhook( payload: &str, signature: &str, delivery_timestamp: i64, ) -> lettermint::Result<()> { Webhook::new(std::env::var("LETTERMINT_WEBHOOK_SECRET").unwrap()) .verify(payload, signature, Some(delivery_timestamp))?; Ok(()) }

The verifier checks the HMAC-SHA256 signature, the signature timestamp, and the optional delivery timestamp. The default timestamp tolerance is five minutes. Do not change the request body before verification. See Webhook signing for the required headers.

Next steps

Crate API reference

Review all public Rust types and methods.

Team API quickstart

Manage domains, projects, routes, and team settings.

Email activity

Review message status and delivery events.

GitHub repository

View the source, report issues, or contribute.

ElixirLaravel
On this page
  • Requirements
  • Install the SDK
  • Send your first email
  • Add email options
    • Recipients and reply-to addresses
    • Metadata and headers
    • Tags
    • Route and tracking settings
    • Attachments and inline images
    • Idempotency
    • Schedule an email
  • Handle errors
  • Use the Team API
  • Verify webhook signatures
  • Next steps
Rust
Rust
Rust
Rust
Rust
Rust
Rust
Rust
Rust
Rust
Rust
Rust