| Crates.io | unsent |
| lib.rs | unsent |
| version | 1.0.3 |
| created_at | 2025-11-19 18:12:32.462331+00 |
| updated_at | 2026-01-14 21:13:46.18926+00 |
| description | Rust SDK for the Unsent API - Send transactional emails with ease |
| homepage | https://unsent.dev |
| repository | https://github.com/souravsspace/unsent-rust |
| max_upload_size | |
| id | 1940539 |
| size | 195,653 |
Official Rust SDK for the Unsent API - Send transactional emails with ease.
Add this to your Cargo.toml:
[dependencies]
unsent = "1.0"
serde_json = "1.0"
use unsent::{Client, models::EmailCreate};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new("un_xxxx")?;
// Use the client
Ok(())
}
You can also set your API key using environment variables:
// Set UNSENT_API_KEY in your environment
// Then initialize without passing the key
let client = Client::new("")?;
use unsent::{Client, models::EmailCreate, emails::EmailsClient};
let client = Client::new("un_xxxx")?;
let emails = EmailsClient::new(&client);
let email = EmailCreate {
to: serde_json::json!("hello@acme.com"),
from: "hello@company.com".to_string(),
subject: Some("Unsent email".to_string()),
html: Some(Some("<p>Unsent is the best email service provider to send emails</p>".to_string())),
text: Some(Some("Unsent is the best email service provider to send emails".to_string())),
..Default::default()
};
let response = emails.send(&email)?;
println!("Email sent! ID: {}", response.id);
use unsent::models::{EmailCreate, Attachment};
let email = EmailCreate {
to: serde_json::json!("hello@acme.com"),
from: "hello@company.com".to_string(),
subject: Some("Email with attachment".to_string()),
html: Some(Some("<p>Please find the attachment below</p>".to_string())),
attachments: Some(vec![
serde_json::json!({
"filename": "document.pdf",
"content": "base64-encoded-content-here"
})
]),
..Default::default()
};
let response = emails.send(&email)?;
use chrono::{Utc, Duration};
let scheduled_time = (Utc::now() + Duration::hours(1)).to_rfc3339();
let email = EmailCreate {
to: serde_json::json!("hello@acme.com"),
from: "hello@company.com".to_string(),
subject: Some("Scheduled email".to_string()),
html: Some(Some("<p>This email was scheduled</p>".to_string())),
scheduled_at: Some(scheduled_time),
..Default::default()
};
let response = emails.send(&email)?;
use unsent::models::EmailBatchItem;
let batch = vec![
EmailBatchItem {
to: serde_json::json!("user1@example.com"),
from: "hello@company.com".to_string(),
subject: Some("Hello User 1".to_string()),
html: Some(Some("<p>Welcome User 1</p>".to_string())),
..Default::default()
},
EmailBatchItem {
to: serde_json::json!("user2@example.com"),
from: "hello@company.com".to_string(),
subject: Some("Hello User 2".to_string()),
html: Some(Some("<p>Welcome User 2</p>".to_string())),
..Default::default()
},
];
let response = emails.batch(&batch)?;
println!("Sent {} emails", response.ids.len());
To prevent duplicate emails when retrying failed requests, you can provide an idempotency key.
use unsent::models::RequestOptions;
let options = RequestOptions {
idempotency_key: Some("unique-key-123".to_string()),
};
let response = emails.send_with_options(&email, &options)?;
let email = emails.get("email_id")?;
println!("Email status: {}", email.data["status"]);
use unsent::models::EmailUpdate;
let update = EmailUpdate {
scheduled_at: None,
};
let response = emails.update("email_id", &update)?;
let response = emails.cancel("email_id")?;
println!("Email cancelled successfully");
use unsent::models::EmailListParams;
let params = EmailListParams {
limit: Some(20),
page: Some(1),
..Default::default()
};
let emails = emails.list(Some(¶ms))?;
// Get bounces
let bounces = emails.bounces(None)?;
// Get complaints
let complaints = emails.complaints(None)?;
// Get unsubscribes
let unsubscribes = emails.unsubscribes(None)?;
use unsent::contact_books::ContactBooksClient;
let client = Client::new("un_xxxx")?;
let books = ContactBooksClient::new(&client);
let book_list = books.list()?;
use unsent::models::ContactBookCreate;
let book = ContactBookCreate {
name: "Newsletter Subscribers".to_string(),
emoji: Some("📧".to_string()),
properties: None,
};
let response = books.create(&book)?;
let book = books.get("book_id")?;
use unsent::models::ContactBookUpdate;
let update = ContactBookUpdate {
name: Some("VIP List".to_string()),
emoji: None,
properties: None,
};
let response = books.update("book_id", &update)?;
let response = books.delete("book_id")?;
// List contacts in a book
let contacts_list = contacts.list("book_id", None)?;
use unsent::{models::ContactCreate, contacts::ContactsClient};
use std::collections::HashMap;
let client = Client::new("un_xxxx")?;
let contacts = ContactsClient::new(&client);
let mut metadata = HashMap::new();
metadata.insert("company".to_string(), serde_json::json!("Acme Inc"));
metadata.insert("role".to_string(), serde_json::json!("Developer"));
let contact = ContactCreate {
email: "user@example.com".to_string(),
first_name: Some("John".to_string()),
last_name: Some("Doe".to_string()),
metadata: Some(metadata),
// Optional fields
phone_number: None,
subscribed: None,
};
let response = contacts.create("contact_book_id", &contact)?;
let contact = contacts.get("contact_book_id", "contact_id")?;
use unsent::models::ContactUpdate;
let mut metadata = HashMap::new();
metadata.insert("role".to_string(), serde_json::json!("Senior Developer"));
let update = ContactUpdate {
first_name: Some("Jane".to_string()),
last_name: None,
metadata: Some(metadata),
// Optional
email: None,
phone_number: None,
subscribed: None,
};
let response = contacts.update("contact_book_id", "contact_id", &update)?;
use unsent::models::ContactUpsert;
let upsert = ContactUpsert {
email: Some("user@example.com".to_string()),
first_name: Some("John".to_string()),
last_name: Some("Doe".to_string()),
metadata: None,
// Optional fields
phone_number: None,
subscribed: None,
};
// Note: Pass upsert struct directly, serialization handles wrapper
let response = contacts.upsert("contact_book_id", "contact_id", &upsert)?;
let response = contacts.delete("contact_book_id", "contact_id")?;
let active_campaigns = campaigns.list().await?;
use unsent::{models::CampaignCreate, campaigns::CampaignsClient};
let client = Client::new("un_xxxx")?;
let campaigns = CampaignsClient::new(&client);
let campaign = CampaignCreate {
name: "Welcome Series".to_string(),
subject: "Welcome to our service!".to_string(),
html: "<p>Thanks for joining us!</p>".to_string(),
from: "welcome@example.com".to_string(),
contact_book_id: "cb_1234567890".to_string(),
// Optional fields
reply_to: None,
cc: None,
bcc: None,
attachments: None,
};
let response = campaigns.create(&campaign)?;
println!("Campaign created! ID: {}", response.campaign.id);
use unsent::models::CampaignSchedule;
let schedule = CampaignSchedule {
scheduled_at: "2024-12-01T10:00:00Z".to_string(),
};
let response = campaigns.schedule(&campaign.id, &schedule)?;
// Pause a campaign
let pause_resp = campaigns.pause("campaign_123")?;
println!("Campaign paused successfully!");
// Resume a campaign
let resume_resp = campaigns.resume("campaign_123")?;
println!("Campaign resumed successfully!");
let campaign_item = campaigns.get("campaign_id")?;
println!("Campaign status: {:?}", campaign_item.status);
println!("Recipients: {:?}", campaign_item.stats.total);
println!("Sent: {:?}", campaign_item.stats.sent);
use unsent::domains::DomainsClient;
let client = Client::new("un_xxxx")?;
let domains = DomainsClient::new(&client);
let domain_list = domains.list()?;
for domain in domain_list {
println!("Domain: {}, Status: {:?}", domain.domain, domain.status);
}
use unsent::models::DomainCreate;
let domain = DomainCreate {
domain: "example.com".to_string(),
};
let response = domains.create(&domain)?;
let response = domains.verify("domain_id")?;
println!("Verification status: {}", response.success);
let domain = domains.get("domain_id")?;
let response = domains.delete("domain_id")?;
Note: Webhooks are currently in development and not fully implemented (server-side). The SDK includes these methods for future compatibility.
use unsent::webhooks::WebhooksClient;
let client = Client::new("un_xxxx")?;
let webhooks = WebhooksClient::new(&client);
let refs = webhooks.list()?;
use unsent::models::WebhookCreate;
let webhook = WebhookCreate {
url: "https://example.com/webhook".to_string(),
events: vec!["email.sent".to_string()],
};
let response = webhooks.create(&webhook)?;
println!("Webhook created! ID: {}", response.id);
let webhook = webhooks.get("webhook_id").await?;
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?;
let response = webhooks.test("webhook_id").await?;
let response = webhooks.delete("webhook_id")?;
use unsent::templates::TemplatesClient;
let client = Client::new("un_xxxx")?;
let templates = TemplatesClient::new(&client);
let template_list = templates.list().await?;
use unsent::models::TemplateCreate;
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?;
let template = templates.get("template_id").await?;
use unsent::models::TemplateUpdate;
let update = TemplateUpdate {
name: Some("Updated Name".to_string()),
subject: None,
html: None,
content: None,
};
let response = templates.update("template_id", &update).await?;
let response = templates.delete("template_id").await?;
use unsent::suppressions::SuppressionsClient;
let client = Client::new("un_xxxx")?;
let suppressions = SuppressionsClient::new(&client);
let suppression_list = suppressions.list(None).await?;
use unsent::models::{AddSuppressionRequest, Reason};
let req = AddSuppressionRequest::new("spam@example.com".to_string(), Reason::Complaint);
let response = suppressions.add(&req).await?;
let response = suppressions.delete("spam@example.com").await?;
use unsent::activity::ActivityClient;
let client = Client::new("un_xxxx")?;
let activity = ActivityClient::new(&client);
let feed = activity.get(None).await?;
use unsent::analytics::AnalyticsClient;
let client = Client::new("un_xxxx")?;
let analytics = AnalyticsClient::new(&client);
// General analytics
let stats = analytics.get().await?;
// Time series
let time_series = analytics.time_series(None).await?;
// Reputation
let reputation = analytics.reputation(None).await?;
use unsent::{metrics::MetricsClient, stats::StatsClient};
let client = Client::new("un_xxxx")?;
// Metrics
let metrics = MetricsClient::new(&client);
let metrics_data = metrics.get(None).await?;
// Stats
let stats = StatsClient::new(&client);
let stats_data = stats.get(None).await?;
use unsent::events::EventsClient;
let client = Client::new("un_xxxx")?;
let events = EventsClient::new(&client);
let event_list = events.list(None).await?;
use unsent::api_keys::ApiKeysClient;
use unsent::models::ApiKeyCreate;
let client = Client::new("un_xxxx")?;
let api_keys = ApiKeysClient::new(&client);
// List
let keys = api_keys.list().await?;
// Create
let new_key = ApiKeyCreate::new("Prod Key".to_string());
let response = api_keys.create(&new_key).await?;
// Delete
let response = api_keys.delete("key_id").await?;
use unsent::{settings::SettingsClient, teams::TeamsClient};
let client = Client::new("un_xxxx")?;
// Settings
let settings_client = SettingsClient::new(&client);
let settings = settings_client.get().await?;
// Teams
let teams_client = TeamsClient::new(&client);
let teams = teams_client.list().await?;
let my_team = teams_client.get().await?;
use unsent::system::SystemClient;
let client = Client::new("un_xxxx")?;
let system = SystemClient::new(&client);
let health = system.health().await?;
let version = system.version().await?;
The SDK uses Rust's Result type for error handling:
use unsent::{Client, UnsentError};
let client = Client::new("un_xxxx")?;
match emails.send(&email) {
Ok(response) => println!("Email sent! ID: {}", response.id),
Err(UnsentError::Api(api_error)) => {
eprintln!("API Error: {} - {}", api_error.code, api_error.message);
}
Err(e) => eprintln!("Error: {}", e),
}
To disable automatic error raising:
let client = Client::new("un_xxxx")?.with_raise_on_error(false);
For advanced use cases, you can provide your own HTTP client:
use reqwest::blocking::Client as HttpClient;
use std::time::Duration;
let http_client = HttpClient::builder()
.timeout(Duration::from_secs(30))
.build()?;
let client = Client::new("un_xxxx")?.with_http_client(http_client);
Client::new(key) - Initialize the client.with_base_url(url) - Set custom base URL.with_http_client(client) - Set custom HTTP client.with_raise_on_error(raise) - Set error handling behavioremails.send(payload) - Send an email (alias for create)emails.create(payload) - Create and send an emailemails.batch(emails) - Send multiple emails in batchemails.get(email_id) - Get email detailsemails.update(email_id, payload) - Update a scheduled emailemails.cancel(email_id) - Cancel a scheduled emailemails.list(params) - List emails with filtersemails.bounces(params) - List bounced emailsemails.complaints(params) - List spam complaintsemails.unsubscribes(params) - List unsubscribescontacts.list(book_id, params) - List contactscontacts.create(book_id, payload) - Create a contactcontacts.get(book_id, contact_id) - Get contact detailscontacts.update(book_id, contact_id, payload) - Update a contactcontacts.upsert(book_id, contact_id, payload) - Upsert a contactcontacts.delete(book_id, contact_id) - Delete a contactcontact_books.list() - List contact bookscontact_books.create(payload) - Create contact bookcontact_books.get(id) - Get contact bookcontact_books.update(id, payload) - Update contact bookcontact_books.delete(id) - Delete contact bookcampaigns.list() - List all campaignscampaigns.create(payload) - Create a campaigncampaigns.get(campaign_id) - Get campaign detailscampaigns.schedule(campaign_id, payload) - Schedule a campaigncampaigns.pause(campaign_id) - Pause a campaigncampaigns.resume(campaign_id) - Resume a campaigndomains.list() - List all domainsdomains.create(payload) - Create a domaindomains.verify(domain_id) - Verify a domaindomains.get(domain_id) - Get domain detailsdomains.delete(domain_id) - Delete a domainwebhooks.list() - List all webhookswebhooks.create(payload) - Create a webhookwebhooks.update(id, payload) - Update a webhookwebhooks.delete(id) - Delete a webhooktemplates.list() - List all templatestemplates.create(payload) - Create a templatetemplates.get(id) - Get template detailstemplates.update(id, payload) - Update a templatetemplates.delete(id) - Delete a templateactivity.get(params) - Get activity feedanalytics.get() - Get email analyticsanalytics.time_series(params) - Get analytics time seriesanalytics.reputation(params) - Get sender reputationmetrics.get(params) - Get performance metricsstats.get(params) - Get email statisticsevents.list(params) - List email eventsapi_keys.list() - List all API keysapi_keys.create(payload) - Create an API keyapi_keys.delete(id) - Delete an API keysettings.get() - Get team settingssystem.health() - Check API healthsystem.version() - Get API versionteams.list() - List all teamsteams.get() - Get current teamsuppressions.list(params) - List suppressed emailssuppressions.add(payload) - Add email to suppression listsuppressions.delete(email) - Remove email from suppression listMIT