Rust
reqwest and serde, with the refusal typed so you can match on the code.
There is no emails.sh crate. reqwest and serde are what almost every Rust service already uses for HTTP and JSON, and the program below is complete.
Dependencies
# Cargo.toml
[package]
name = "acme-email"
version = "0.1.0"
edition = "2021"
[dependencies]
reqwest = { version = "0.12", features = ["json", "rustls-tls"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }Send
// src/main.rs
use serde::{Deserialize, Serialize};
use std::env;
#[derive(Serialize)]
struct Send<'a> {
from: &'a str,
to: Vec<&'a str>,
subject: &'a str,
html: &'a str,
}
#[derive(Deserialize)]
struct Queued {
id: String,
status: String,
}
#[derive(Deserialize)]
struct Refusal {
error: RefusalBody,
}
#[derive(Deserialize)]
struct RefusalBody {
code: String,
message: String,
next: Option<String>,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// The key comes from https://emails.sh/dashboard/api-keys.
let key = env::var("EMAILSSH_API_KEY").expect("EMAILSSH_API_KEY is not set");
let response = reqwest::Client::new()
.post("https://emails.sh/v1/emails")
.bearer_auth(key)
.json(&Send {
from: "Acme <hello@acme.com>",
to: vec!["ada@example.com"],
subject: "Your receipt from Acme",
html: "<p>Thanks for your order.</p>",
})
.send()
.await?;
if response.status().is_client_error() || response.status().is_server_error() {
let refusal: Refusal = response.json().await?;
// next says what to do about it, in prose.
eprintln!(
"refused: {}: {} {}",
refusal.error.code,
refusal.error.message,
refusal.error.next.unwrap_or_default()
);
std::process::exit(1);
}
let queued: Queued = response.json().await?;
println!("queued {} ({})", queued.id, queued.status);
Ok(())
}Blocking, without an async runtime
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json", "rustls-tls"] }
use serde_json::json;
use std::env;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let key = env::var("EMAILSSH_API_KEY")?;
let response = reqwest::blocking::Client::new()
.post("https://emails.sh/v1/emails")
.bearer_auth(key)
.json(&json!({
"from": "Acme <hello@acme.com>",
"to": ["ada@example.com"],
"subject": "Your receipt from Acme",
"html": "<p>Thanks for your order.</p>"
}))
.send()?;
println!("{}", response.text()?);
Ok(())
}