Render25 — High-performance transactional email platform. Now available.
Client SDKs

Rust SDK

The official Render25 Rust crate. Asynchronous, high-performance, and type-safe using tokio and reqwest.

Rust 2021 Editioncrates.io: render25Async / Tokio

Installation

bash
cargo add render25 tokio --features tokio/full

Or add manually to Cargo.toml:

Cargo.toml
[dependencies]
render25 = "1.0"
tokio = { version = "1.0", features = ["full"] }

Basic Usage

Initialize the client. It automatically detects RENDER25_API_KEY from the environment.

src/main.rs
use render25::{Render25, SendEmailOptions};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    // Reads RENDER25_API_KEY automatically from environment
    let client = Render25::new(None)?;

    let response = client.emails.send(SendEmailOptions {
        from: "support@yourdomain.com".to_string(),
        to: vec!["customer@example.com".to_string()],
        subject: "Welcome to Render25!".to_string(),
        html: Some("<h1>Welcome aboard!</h1><p>Transactional email sent via Rust.</p>".to_string()),
        text: Some("Welcome aboard! Transactional email sent via Rust.".to_string()),
        ..Default::default()
    }).await?;

    println!("Dispatched Message ID: {}", response.id);
    Ok(())
}

Note

Set RENDER25_API_KEY in your environment variables.

CC, BCC & Custom Reply-To

src/advanced.rs
use render25::{Render25, SendEmailOptions};

async fn send_invoice_notification(client: &Render25) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    client.emails.send(SendEmailOptions {
        from: "support@yourdomain.com".to_string(),
        to: vec!["client@example.com".to_string()],
        cc: Some(vec!["manager@example.com".to_string()]),
        bcc: Some(vec!["archive@example.com".to_string()]),
        reply_to: Some("helpdesk@yourdomain.com".to_string()),
        subject: "Order #1042 Confirmed".to_string(),
        html: Some("<p>Your order has been confirmed.</p>".to_string()),
        ..Default::default()
    }).await?;

    Ok(())
}

File Attachments

Attach files by passing raw bytes with Attachment::from_bytes:

src/attachments.rs
use render25::{Attachment, Render25, SendEmailOptions};

async fn send_receipt(client: &Render25) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let pdf_bytes = std::fs::read("invoice.pdf")?;

    client.emails.send(SendEmailOptions {
        from: "billing@yourdomain.com".to_string(),
        to: vec!["client@example.com".to_string()],
        subject: "Your Invoice #1042".to_string(),
        html: Some("<p>Your invoice is attached below.</p>".to_string()),
        attachments: Some(vec![
            Attachment::from_bytes("invoice_1042.pdf", &pdf_bytes, Some("application/pdf")),
        ]),
        ..Default::default()
    }).await?;

    Ok(())
}

Axum Web Framework Example

src/main.rs
use axum::{routing::post, Json, Router};
use render25::{Render25, SendEmailOptions};
use serde::{Deserialize, Serialize};
use std::sync::Arc;

#[derive(Deserialize)]
struct WelcomeRequest {
    email: String,
    name: String,
}

#[derive(Serialize)]
struct WelcomeResponse {
    success: bool,
    message_id: String,
}

#[tokio::main]
async fn main() {
    let client = Arc::new(Render25::new(None).expect("Invalid Render25 client"));

    let app = Router::new().route("/send-welcome", post({
        let client = Arc::clone(&client);
        move |Json(payload): Json<WelcomeRequest>| {
            let client = Arc::clone(&client);
            async move {
                let res = client.emails.send(SendEmailOptions {
                    from: "welcome@yourdomain.com".to_string(),
                    to: vec![payload.email],
                    subject: format!("Welcome {}!", payload.name),
                    html: Some(format!("<h1>Welcome {}!</h1>", payload.name)),
                    ..Default::default()
                }).await.unwrap();

                Json(WelcomeResponse {
                    success: true,
                    message_id: res.id,
                })
            }
        }
    }));

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}