By using our site, you agree to our use of cookies. Cookie Policy
For developers

Email infrastructure that gets out of your way.

A REST API you can read in one sitting, an SMTP relay for the stack you already have, and official SDKs in the language you work in. Send from your application, keep the message ID, and get back to the product.

One POST to send. One header to authenticate. Attachments, cc, bcc, reply-to, custom headers, and React Email are supported. Sending runs on AWS SES.

Send an email in one request.Example request
curl --request POST \
  'https://api.email.utobo.com/functions/v1/send-email' \
  --header 'Authorization: Bearer av_live_...' \
  --header 'Content-Type: application/json' \
  --data '{
    "from": "Northstar <hello@example.com>",
    "to": "alex@example.net",
    "subject": "Your workspace is ready",
    "html": "<p>Sign in to start your first project.</p>"
  }'
Example response{ "id": "3c9b0f4e-7a2d-4f8b-9c1e-5d6a8b3f2e1c",
"message": "Email sent." }

Keep the ID. A successful response means the message was accepted for sending — not that it reached an inbox.

Server-side · REST API

Send from an address on your verified domain. Nothing on this page sends email.

Why developers pick it

Small surface area. Predictable behaviour.

One POST sends an email.

Give the endpoint from, to, subject and html. Add reply-to, cc, bcc, attachments or custom headers when a message needs them. There is no proprietary envelope format to learn first.

One header authenticates.

Send Authorization: Bearer av_live_… and you are through. No signing steps, no token exchange, no separate auth path for the SDKs. The full key is shown once at creation, so keep it in your server environment.

Errors say what to fix.

Every failure returns { error, name, message }. Branch on the machine-readable name — a missing field and an unverified domain are different problems, and the response tells you which one you have.

No lock-in

Standard REST. Standard SMTP. Nothing proprietary.

utobo email speaks the two interfaces your stack already speaks. If your application can make an HTTPS request or open an SMTP connection, it can send through utobo — and it can send through something else tomorrow. Leaving is a change of host and credentials, not a rewrite.

Sending runs on AWS SES. Add your own sending domain, complete DKIM, SPF and DMARC in the setup flow, and let automatic bounce and complaint handling keep the suppression list current without a job of your own.

Already sending over SMTP? Point your existing mailer at smtp.mail.utobo.com. The username is the literal word apikey — your API key goes in the password field.

See the full SMTP setup ↗
SMTP relayConnection settings
Host
smtp.mail.utobo.com
Ports
587 · STARTTLS
465 · implicit TLS
Username
apikey
Password
av_live_...

The username is always apikey, never an email address. Store the key in the application’s secure settings, not in source control.

Use the same verified sending domain you use on the API.

The whole surface

Two endpoints to learn. The rest is your application.

Everything lives under https://api.email.utobo.com/functions/v1. One call sends the message, the other looks it up again.

EndpointWhat it doesWhat you get back
POST /functions/v1/send-emailSend one message to up to 50 combined recipients.Supports reply-to, cc, bcc, attachments and custom headers.{ "id": "…", "message": "Email sent." }
GET /functions/v1/send-email/:idLook a message up by the ID the send response returned.The place to start when someone asks where an email went.The status record for that message
  • REST API over JSON, with an API key scoped to what the integration actually needs
  • SMTP relay on smtp.mail.utobo.com, ports 587 or 465
  • Official SDKs for Node.js, Python, Ruby and Go — PHP coming soon
  • React Email support in the Node SDK, rendered to HTML for you
  • Custom sending domain with DKIM, SPF and DMARC setup
  • Automatic bounce and complaint handling with suppression
  • Message lookup by ID, so a support question has somewhere to start
  • Inbound replies on your own domain with a single MX record

Features are not a pricing tier. Transactional starts at $9 a month for 10,000 emails, and AI drafting is included on every plan at no extra cost. Compare the three tracks ↗

Limits and failures

Handle the bad path before you ship the good one.

Error handling stays in the application that made the request. Branch on name, not on the wording of message.

400

Fix the request.

validation_error — a field is missing or malformed. Correct the payload and retry; this one will not resolve itself.

401

Check the key.

unauthorized — the API key is missing, revoked or mistyped. Confirm the header reads Authorization: Bearer av_live_…

403

Widen the scope.

insufficient_scope — the key is valid but not permitted to do this. Issue a key with the access this integration needs.

422

Check the sender.

domain_not_verified — the from-address is not on a verified domain, or every recipient is suppressed.

429

Back off, then retry.

rate_limit_exceeded — you are sending faster than your allowance. Wait for the returned Retry-After window before the next attempt.

100 requests/minute/key500 requests/minute/organization50 combined recipients/request

Queue and pace bulk work rather than retrying immediately on 429. Expecting heavier volume? Talk through your requirements ↗

From install to first send

Start in the language you already use.

The Node.js SDK is the official library. Python, Ruby and Go are published too, and every one of them talks to the same two endpoints.

Node.jsExample integration
npm install utobo-email
import { UtoboEmail } from 'utobo-email';

const apiKey = process.env.UTOBO_EMAIL_API_KEY;
if (!apiKey) throw new Error('Set UTOBO_EMAIL_API_KEY on the server.');

const client = new UtoboEmail(apiKey);
const { data, error } = await client.emails.send({
  from: 'Northstar <hello@example.com>',
  to: 'alex@example.net',
  subject: 'Your workspace is ready',
  html: '<p>Sign in to start your first project.</p>',
});

if (error) console.error(error);
else console.log(data);
Node.jsnpm install utobo-emailOpen package ↗
Pythonpip install utobo-emailOpen package ↗
Rubygem install utobo-emailOpen package ↗
Gogo get github.com/myutobo/utobo-email-goOpen package ↗
PHP# Coming soon — send from PHP today with the REST API or SMTPComing soon
  1. 01

    Verify your domain.

    Add the DKIM, SPF and DMARC records from the setup flow and wait for verification before sending from that address.

  2. 02

    Create a scoped key.

    Copy av_live_… once at creation and load it from UTOBO_EMAIL_API_KEY on the server.

  3. 03

    Send one test.

    Use curl or your SDK to send a short message to an address you control. Confirm the response carries an ID.

  4. 04

    Wire it to an event.

    Move the call behind the signup, reset or receipt that should trigger it, and store the returned ID with that record.

Open the full quickstart in the docs ↗

Good questions

A few things you might be wondering.

The detail worth checking before you write the integration.

Talk to the team ↗
Which endpoints do I actually need?

Two. POST /functions/v1/send-email sends a message and GET /functions/v1/send-email/:id looks one up, both under https://api.email.utobo.com/functions/v1. See the request and response shapes.

What are the rate limits?

100 requests per minute per key and 500 per minute per organization, with a maximum of 50 combined recipients on a single request. Exceeding them returns 429 rate_limit_exceeded with a Retry-After header to wait on.

Can I use SMTP instead of the API?

Yes, and you can mix the two. Connect to smtp.mail.utobo.com on port 587 with STARTTLS or 465 with implicit TLS. The username is the literal word apikey and the password is your API key. See the SMTP settings.

Is there a PHP SDK?

A native PHP SDK is coming soon. Node.js, Python, Ruby and Go are published today, and PHP can send right now through the REST API or the SMTP relay with any HTTP or mail library. Choose your language.

How hard is it to leave?

As hard as changing a base URL and a credential. There is no proprietary transport or template format in the sending path — it is HTTPS with JSON, or SMTP. Anything you build against it stays portable.

Does a successful response mean the email was delivered?

No. It means the message was accepted for sending. Delivery is decided by the recipient’s mail system, so keep the returned ID and check the message record rather than treating a 200 as proof of inbox placement.

What does it cost to start?

Transactional starts at $9 a month for 10,000 emails. Promotional starts at $19 a month for 2,500 contacts with unlimited campaign sends — you pay for contacts, not sends — and All-in-one starts at $24 a month. AI is included on every plan. See the plans.

Two endpoints, one header, and your next release ships.

Create a key, verify a domain, and send your first message in an afternoon. Transactional starts at $9 a month for 10,000 emails, with AI included.