Temp mail
in Rust.
Disposable inboxes and OTP extraction for Rust — plain HTTP, no SDK.
use serde_json::{json, Value};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let key = std::env::var("EVILMAIL_KEY")?;
let res: Value = reqwest::blocking::Client::new()
.post("https://evilmail.pro/api/temp-email")
.header("X-API-Key", key)
.json(&json!({ "ttlMinutes": 30 }))
.send()?
.json()?;
let email = res["data"]["email"].as_str().unwrap_or("");
println!("Inbox: {email}");
Ok(())
}Spinning up a Rust temp mail inbox lets you test signup flows, email verification, and OTP delivery without a real mailbox or a flaky shared account. EvilMail exposes a plain HTTP API: create a disposable inbox, poll it for incoming mail, and pull the confirmation code straight into your integration tests or CI pipeline. There's no SMTP server to run and no SDK to vendor — just reqwest, serde_json, and an API key from an environment variable.
Why use temp mail in Rust
End-to-end signup tests
Register a real account against your staging environment using a fresh disposable email, then assert that the welcome or verification message actually lands. No shared inbox to clean up between runs.
OTP & 2FA automation
Wait for the login or verification email, regex the six-digit code out of the body, and feed it back into your flow. Ideal for testing passwordless and two-factor logins in Rust.
CI pipeline email checks
Read the API key from an environment variable and run the whole create-poll-read cycle inside GitHub Actions or GitLab CI. Every build gets a clean, isolated mailbox.
Scraping confirmation links
Grab activation URLs or magic links from the message text or HTML, follow them with reqwest, and verify the full onboarding path works without a human in the loop.
The flow — Rust temp mail in 3 calls
Create a disposable inbox
use serde_json::{json, Value};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let key = std::env::var("EVILMAIL_KEY")?;
let client = reqwest::blocking::Client::new();
// Ask EvilMail for a fresh inbox that lives 30 minutes.
let res: Value = client
.post("https://evilmail.pro/api/temp-email")
.header("X-API-Key", &key)
.json(&json!({ "ttlMinutes": 30 }))
.send()?
.json()?;
let email = res["data"]["email"].as_str().unwrap_or("");
let token = res["data"]["sessionToken"].as_str().unwrap_or("");
println!("Inbox {email} ready (token {token})");
Ok(())
}Poll until the email arrives
use serde_json::Value;
use std::{thread::sleep, time::Duration};
// Poll the session ~20 times, 3s apart, until mail lands.
fn wait_for_message(
client: &reqwest::blocking::Client,
key: &str,
token: &str,
) -> Result<u64, Box<dyn std::error::Error>> {
let url =
format!("https://evilmail.pro/api/temp-email/{token}");
for _ in 0..20 {
let res: Value = client
.get(&url)
.header("X-API-Key", key)
.send()?
.json()?;
// messages is empty until something is delivered.
if let Some(msg) = res["data"]["messages"].get(0) {
let uid = msg["uid"].as_u64().unwrap_or(0);
let subject = msg["subject"].as_str().unwrap_or("");
println!("Got mail: {subject} (uid {uid})");
return Ok(uid);
}
sleep(Duration::from_secs(3));
}
Err("timed out waiting for email".into())
}Read the message & extract the code
use regex::Regex;
use serde_json::Value;
// Fetch the message body and pull out a 6-digit OTP.
fn extract_code(
client: &reqwest::blocking::Client,
key: &str,
token: &str,
uid: u64,
) -> Result<Option<String>, Box<dyn std::error::Error>> {
let url = format!(
"https://evilmail.pro/api/message/{uid}?token={token}"
);
let res: Value = client
.get(&url)
.header("X-API-Key", key)
.send()?
.json()?;
let body = res["data"]["text"].as_str().unwrap_or("");
// A one-time code is six consecutive digits.
let re = Regex::new(r"\b(\d{6})\b")?;
let code = re.captures(body).map(|c| c[1].to_string());
match &code {
Some(c) => println!("OTP = {c}"),
None => println!("No 6-digit code found"),
}
Ok(code)
}Rust temp mail — FAQ
Q1How do I get a temp mail address in Rust?−
Send a POST to https://evilmail.pro/api/temp-email with your X-API-Key header and a JSON body like {"ttlMinutes": 30}. The response contains data.email (the disposable address) and data.sessionToken, which you use to poll and read messages. See the hero snippet — it's about ten lines with reqwest and serde_json.
Q2Can I use this for automated testing?+
Yes — that's the primary use case. Read the API key from an environment variable, generate a fresh inbox per test, and run the create-poll-read cycle inside your integration suite or CI. Because each inbox is isolated and short-lived, tests don't interfere with one another and there's nothing to clean up.
Q3How do I extract the OTP?+
Call GET /api/message/{uid}?token={sessionToken} to fetch the message, then run a regex over data.text (or data.html). For a standard six-digit one-time code the pattern \b(\d{6})\b works; capture group 1 is the code. The step 3 snippet shows this with the regex crate.
Q4Do I need an API key / are there rate limits?+
Yes, every request needs the X-API-Key header — keep the key in an environment variable such as EVILMAIL_KEY rather than hard-coding it. Requests are rate limited per key, so when polling, stick to a sensible interval (the examples use 3 seconds between the ~20 poll attempts) instead of tight-looping.
Q5How long does the inbox live?+
You control it with the ttlMinutes field when creating the inbox — the examples use 30 minutes. Once the TTL expires the address and its messages are discarded, so poll and read the message within that window. For most verification and OTP flows a short TTL of 10 to 30 minutes is plenty.
Temp mail in other languages
One API key. Disposable inboxes at scale.
Create unlimited throwaway addresses, poll them over HTTP, and pull verification codes straight into your tests and CI. Free to start; custom domains and higher limits on paid plans.

