unsent
unsent.dev
Get Started

Rust

Official Unsent Rust SDK for sending emails and managing contacts.

This guide shows how to install and use the official unsent Rust SDK.

Installation

Add the unsent crate to your Cargo.toml file:

[dependencies]
unsent = "1.0"
serde_json = "1.0"

Initialize

Initialize the client with your API key.

use unsent::Client;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new("un_xxx")?;
    Ok(())
}

Send an email

Now you can send an email. First, create an EmailsClient using your initialized client. Then, define an EmailCreate struct with your email details and pass it to the send method.

use unsent::{Client, models::EmailCreate, emails::EmailsClient};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new("un_xxx")?;
    let emails = EmailsClient::new(&client);

    let email = EmailCreate {
        to: serde_json::json!("user@example.com"),
        from: "no-reply@yourdomain.com".to_string(),
        subject: Some("Welcome".to_string()),
        html: Some(Some("<strong>Hello!</strong>".to_string())),
        text: None,
        ..Default::default()
    };

    let response = emails.send(&email)?;
    println!("Email sent! ID: {}", response.id);
    
    Ok(())
}

With attachments and scheduling

You can also send emails with attachments and schedule them for later delivery.

  • Attachments: Create a vector of serde_json::Value objects representing the attachments.
  • Scheduling: Use the scheduled_at field with an RFC 3339 formatted string.
use unsent::models::EmailCreate;
use chrono::{Utc, Duration};

// Calculate a time 10 minutes from now
let scheduled_time = (Utc::now() + Duration::minutes(10)).to_rfc3339();

let email = EmailCreate {
    to: serde_json::json!("user@example.com"),
    from: "no-reply@yourdomain.com".to_string(),
    subject: Some("Report".to_string()),
    text: Some(Some("See attached.".to_string())),
    attachments: Some(vec![
        serde_json::json!({
            "filename": "report.txt",
            "content": "SGVsbG8gd29ybGQ=" // Content must be Base64 encoded
        })
    ]),
    scheduled_at: Some(scheduled_time),
    ..Default::default()
};

let response = emails.create(&email)?;

Batch send

To send multiple emails efficiently in a single request, use the batch method with a vector of EmailBatchItem structs.

use unsent::models::EmailBatchItem;

let batch = vec![
    EmailBatchItem {
        to: serde_json::json!("a@example.com"),
        from: "no-reply@yourdomain.com".to_string(),
        subject: Some("A".to_string()),
        html: Some(Some("<p>A</p>".to_string())),
        ..Default::default()
    },
    EmailBatchItem {
        to: serde_json::json!("b@example.com"),
        from: "no-reply@yourdomain.com".to_string(),
        subject: Some("B".to_string()),
        html: Some(Some("<p>B</p>".to_string())),
        ..Default::default()
    },
];

let response = emails.batch(&batch)?;
println!("Sent {} emails", response.ids.len());

Idempotent Retries

To safely retry requests, you can use RequestOptions with the _with_options methods.

use unsent::models::RequestOptions;

let options = RequestOptions {
    idempotency_key: Some("unique-key-123".to_string()),
};

// For single email
emails.send_with_options(&email, &options)?;

// For batch emails
emails.batch_with_options(&batch, &options)?;

Retrieve and manage emails

You can retrieve details of sent emails, update scheduled emails, or cancel them.

Get an email

Fetch the status and details of a specific email using its ID:

let email = emails.get("email_123")?;
println!("Email status: {}", email.data["status"]);

Update schedule time

Change the scheduled delivery time for a pending email:

use unsent::models::EmailUpdate;
use chrono::{Utc, Duration};

let new_time = (Utc::now() + Duration::hours(1)).to_rfc3339();

let update = EmailUpdate {
    scheduled_at: Some(new_time),
};

let response = emails.update("email_123", &update)?;

Cancel a scheduled email

Cancel a scheduled email so it won't be sent:

let response = emails.cancel("email_123")?;
println!("Email cancelled successfully");

List Emails

List previously sent emails with pagination.

use unsent::models::EmailListParams;

let params = EmailListParams {
    limit: Some(20),
    page: Some(1),
    ..Default::default()
};

let email_list = emails.list(Some(&params)).await?;

Email Statistics

Get statistics on your email delivery.

// Bounces
let bounces = emails.bounces(None).await?;

// Complaints
let complaints = emails.complaints(None).await?;

// Unsubscribes
let unsubscribes = emails.unsubscribes(None).await?;

Contact Books

Organize your contacts into books.

List Contact Books

use unsent::contact_books::ContactBooksClient;

let client = Client::new("un_xxxx")?;
let books = ContactBooksClient::new(&client);

let book_list = books.list().await?;

Manage Contact Books

use unsent::models::{ContactBookCreate, ContactBookUpdate};

// Create
let book = ContactBookCreate {
    name: "Newsletter".to_string(),
    emoji: Some("📧".to_string()),
    properties: None,
};
let response = books.create(&book).await?;

// Get
let book_details = books.get("book_id").await?;

// Update
let update = ContactBookUpdate {
    name: Some("VIPs".to_string()),
    emoji: None,
    properties: None,
};
let response = books.update("book_id", &update).await?;

// Delete
let response = books.delete("book_id").await?;

Contacts

Manage your contacts and organize them into contact books. All contact operations require a contact book ID.

List Contacts

// List contacts in a book
let contacts_list = contacts.list("book_id", None).await?;

Create a contact

Add a new contact to a specific contact book. You can include custom metadata using a HashMap.

use unsent::{models::ContactCreate, contacts::ContactsClient};
use std::collections::HashMap;

let client = Client::new("un_xxx")?;
let contacts = ContactsClient::new(&client);

let mut metadata = HashMap::new();
metadata.insert("plan".to_string(), serde_json::json!("pro"));

let contact = ContactCreate {
    email: "user@example.com".to_string(),
    first_name: Some("Jane".to_string()),
    last_name: None,
    metadata: Some(metadata),
    ..Default::default()
};

let response = contacts.create("book_123", &contact)?;

Get a contact

Retrieve a contact's details:

let contact = contacts.get("book_123", "contact_456")?;

Update a contact

Update a contact's information:

use unsent::models::ContactUpdate;

let mut metadata = HashMap::new();
metadata.insert("plan".to_string(), serde_json::json!("enterprise"));

let update = ContactUpdate {
    first_name: Some("John".to_string()),
    last_name: None,
    metadata: Some(metadata),
    
    // Optional
    email: None,
    phone_number: None,
    subscribed: None,
};

let response = contacts.update("book_123", "contact_456", &update)?;

Upsert a contact

Use upsert to create a contact if they don't exist, or update them if they do.

use unsent::models::ContactUpsert;

let upsert = ContactUpsert {
    email: Some("user@example.com".to_string()),
    first_name: Some("Jane".to_string()),
    last_name: None,
    metadata: None,
    ..Default::default()
};

let response = contacts.upsert("book_123", "contact_456", &upsert)?;

Delete a contact

Remove a contact from a book:

let response = contacts.delete("book_123", "contact_456")?;

Campaigns

Campaigns allow you to send emails to all contacts in a specific contact book.

List Campaigns

let active_campaigns = campaigns.list().await?;

Create a campaign

Create a new campaign by defining its content and the target contact book.

use unsent::{models::CampaignCreate, campaigns::CampaignsClient};

let client = Client::new("un_xxx")?;
let campaigns = CampaignsClient::new(&client);

let campaign = CampaignCreate {
    name: "Welcome Series".to_string(),
    subject: "Welcome!".to_string(),
    html: "<p>Thanks for joining us!</p>".to_string(),
    from: "welcome@yourdomain.com".to_string(),
    contact_book_id: "book_123".to_string(),
    ..Default::default()
};

let response = campaigns.create(&campaign)?;
println!("Campaign created! ID: {}", response.campaign.id);

Schedule a campaign

Schedule the campaign to be sent at a specific time.

use unsent::models::CampaignSchedule;

let schedule = CampaignSchedule {
    scheduled_at: "2024-12-01T10:00:00Z".to_string(),
};

let response = campaigns.schedule(&campaign.id, &schedule)?;

Pause and resume campaigns

Control the delivery of your campaign.

// Pause
let pause_resp = campaigns.pause("campaign_123")?;
println!("Campaign paused successfully!");

// Resume
let resume_resp = campaigns.resume("campaign_123")?;
println!("Campaign resumed successfully!");

Domains

Manage your sending domains.

List domains

Get a list of all domains and their statuses.

use unsent::domains::DomainsClient;

let client = Client::new("un_xxx")?;
let domains = DomainsClient::new(&client);

let domain_list = domains.list()?;
for domain in domain_list {
    println!("Domain: {}, Status: {:?}", domain.domain, domain.status);
}

Create a domain

Register a new domain for sending.

use unsent::models::DomainCreate;

let domain = DomainCreate {
    domain: "yourdomain.com".to_string(),
};

let response = domains.create(&domain)?;

Verify a domain

Check the verification status of a domain.

let response = domains.verify("domain_id")?;
println!("Verification status: {}", response.success);

Get Domain

let domain = domains.get("domain_id").await?;

Delete Domain

let response = domains.delete("domain_id").await?;

Templates

Manage your email templates.

use unsent::{models::TemplateCreate, templates::TemplatesClient};

let client = Client::new("un_xxx")?;
let templates = TemplatesClient::new(&client);

// List templates
let response = templates.list().await?;

// Create a template
let template = TemplateCreate {
    name: "Welcome Email".to_string(),
    subject: "Welcome!".to_string(),
    html: Some("<h1>Welcome</h1>".to_string()),
    content: Some("Welcome".to_string()),
};
let response = templates.create(&template).await?;

Activity

Get activity feed for your account.

use unsent::{models::ActivityParams, activity::ActivityClient};

let client = Client::new("un_xxx")?;
let activity = ActivityClient::new(&client);

let params = ActivityParams {
    limit: Some(10),
    ..Default::default()
};

let response = activity.get(Some(&params)).await?;

Analytics

Get email analytics and reporting.

use unsent::analytics::AnalyticsClient;

let client = Client::new("un_xxx")?;
let analytics = AnalyticsClient::new(&client);

// Get general analytics
let stats = analytics.get().await?;

// Get time series data
let time_series = analytics.time_series(None).await?;

// Get sender reputation
let reputation = analytics.reputation(None).await?;

Metric & Stats

Get performance metrics and delivery statistics.

use unsent::{metrics::MetricsClient, stats::StatsClient};

let client = Client::new("un_xxx")?;

// Metrics
let metrics = MetricsClient::new(&client);
let data = metrics.get(None).await?;

// Stats
let stats_client = StatsClient::new(&client);
let stats_data = stats_client.get(None).await?;

Events

List email events with optional filtering.

use unsent::{models::EventsListParams, events::EventsClient};

let client = Client::new("un_xxx")?;
let events = EventsClient::new(&client);

let params = EventsListParams {
    status: Some("DELIVERED".to_string()),
    limit: Some(20),
    ..Default::default()
};

let response = events.list(Some(&params)).await?;

API Keys

Manage your API keys programmatically.

use unsent::{models::ApiKeyCreate, api_keys::ApiKeysClient};

let client = Client::new("un_xxx")?;
let api_keys = ApiKeysClient::new(&client);

// List keys
let keys = api_keys.list().await?;

// Create key
let new_key = ApiKeyCreate::new("Production Key".to_string());
let response = api_keys.create(&new_key).await?;

// Delete key
let response = api_keys.delete("key_id").await?;

Suppressions

Manage suppression lists (bounces, complaints, unsubscribes).

use unsent::{models::{AddSuppressionRequest, Reason}, suppressions::SuppressionsClient};

let client = Client::new("un_xxx")?;
let suppressions = SuppressionsClient::new(&client);

// List suppressions
let list = suppressions.list(None).await?;

// Add to suppression list
let req = AddSuppressionRequest::new("spam@example.com".to_string(), Reason::Complaint);
let response = suppressions.add(&req).await?;

// Remove from suppression list
let response = suppressions.delete("spam@example.com").await?;

Webhooks

Manage webhooks for real-time event notifications.

use unsent::{models::WebhookCreate, webhooks::WebhooksClient};

let client = Client::new("un_xxx")?;
let webhooks = WebhooksClient::new(&client);

// Create webhook
let webhook = WebhookCreate {
    url: "https://api.myapp.com/webhooks".to_string(),
    events: vec!["email.sent".to_string(), "email.delivered".to_string()],
};
let response = webhooks.create(&webhook).await?;

// List webhooks
let hooks = webhooks.list().await?;

Get Webhook

let webhook = webhooks.get("webhook_id").await?;

Update Webhook

use unsent::models::WebhookUpdate;

let update = WebhookUpdate {
    url: Some("https://example.com/new-webhook".to_string()),
    events: None,
};

let response = webhooks.update("webhook_id", &update).await?;

Test Webhook

let response = webhooks.test("webhook_id").await?;

Delete Webhook

let response = webhooks.delete("webhook_id").await?;

System & Teams

Access system health and team information.

use unsent::{system::SystemClient, teams::TeamsClient};

let client = Client::new("un_xxx")?;

// System
let system = SystemClient::new(&client);
let health = system.health().await?;

// Teams
let teams = TeamsClient::new(&client);
let my_team = teams.get().await?;

Error handling

The SDK uses Rust's Result type for error handling. You can match on the result to handle success or failure.

use unsent::{Client, UnsentError};

let client = Client::new("un_xxx")?;

match emails.send(&email) {
    Ok(response) => println!("Email sent! ID: {}", response.id),
    Err(UnsentError::Api(api_error)) => {
        // Handle API errors (e.g., invalid API key, validation errors)
        eprintln!("API Error: {} - {}", api_error.code, api_error.message);
    }
    Err(e) => eprintln!("Error: {}", e),
}

Disable Automatic Error Raising

If you prefer not to have the client return an error for non-2xx responses (though in Rust, Result is idiomatic), you can configure the client:

let client = Client::new("un_xxx")?.with_raise_on_error(false);

Custom HTTP client

For advanced use cases, such as adding custom timeouts or proxies, you can provide your own reqwest client.

use reqwest::blocking::Client as HttpClient;
use std::time::Duration;

// Create a custom HTTP client with a timeout
let http_client = HttpClient::builder()
    .timeout(Duration::from_secs(30))
    .build()?;

// Initialize the SDK with the custom client
let client = Client::new("un_xxx")?.with_http_client(http_client);

Resources