Send emails with Rust
Install the Rust crate from GitHub and call emails().send.
What you'll build
A Rust program that sends a receipt email with the postshiba crate and prints the queued message.
Before you start
- An API key with Send only access. Full access also works. See Create an API key. Support keys cannot send.
- A verified sending domain. See Add and verify a domain.
frommust be an address on it. - A cluster that is ready to send (
sending_readyistrue). See Clusters.
Install
The crate is on GitHub, not crates.io. Add it and serde_json to Cargo.toml. The client is blocking, so no async runtime is needed.
Send your first email
Pass your API key to Client::new, then call emails().send with a serde_json::Value. team_id is only needed for team-scoped calls such as listing clusters, and those calls need a Full access key that stays out of your deployed app. It is on the API keys page.
Put this in src/main.rs and run cargo run. emails().send returns Result<Value, Error>, and the value is the JSON body of the 201 response. The message then shows under Events in the dashboard.
Pin a cluster
Without a pin, PostShiba uses your first cluster that is ready to send. Call send_with with your cluster id to choose one.
Attachments and templates
Attach a file
Add attachments with filename, content_type, and base64 content. Up to 10 files, 18 MB in total. See Attachments for allowed types. This sample uses the base64 crate for encoding.
Send a published template
Pass template with the alias or public id and its variables. Leave out html and text.
Keep the key safe
Use a Send only key in your app. It can send email and call GET /api/v1/users/me. Every other request returns 403 forbidden.
| If this key leaks | Send only | Full access |
|---|---|---|
| Send mail from your verified domains | Yes | Yes |
| Read events, recipients, templates, and sent messages | No | Yes |
| See SMTP passwords and webhook secrets | No | Yes |
| Change clusters, domains, credentials, webhooks, and suppressions | No | Yes |
- Keep Full access keys for setup scripts, the CLI, and MCP. Don't deploy one with your app.
- Read the key with
std::env::var("POSTSHIBA_API_KEY")instead of a string in your code. Don't commit it, log it, or put it in a URL. - Send from your server. Never put a key, even a Send only key, in browser or mobile code.
- Create one key per app and environment. If a key leaks, delete it on API keys and create a new one. Deleting stops it straight away.
Troubleshooting
A response outside 2xx returns postshiba::Error, a struct with error and field as Option<String> and message as String.
| Status | error |
What to do |
|---|---|---|
401 |
Invalid token or no user signed in |
The API key is missing, mistyped, or deleted. Copy it again from API keys. |
403 |
forbidden |
Support keys cannot send. A Send only key gets this on any call other than sending. |
403 |
domain_unverified |
from is not on a verified domain. |
403 |
kyc_required |
Your team is pending production approval. Until then, send only to team members, live inbox addresses, and inbox forward-to addresses. |
422 |
invalid |
field names the problem, such as a missing to, an unpublished template, or a rejected attachment. |
429 |
throttled |
The cluster hit its hourly throttle or 24-hour cap. The client does not retry, and retrying right away hits the same cap. See What happens at your cap. |
429 |
rate_limited |
More than 300 send requests in one minute on one API key. Slow down. |
Every other status is on Errors.
Next steps
- Unique args to get your own ids back on delivery webhooks.
- Managing webhooks to receive delivery events.
- Send emails with SMTP if you already use
lettre. - SDKs for every language client.