PostShiba is in private beta to ensure healthy delivery for all our early customers. Join the waitlist

Email infrastructure for SaaS platforms.

Build on the same platform used to power Image Bento's email infrastructure. Outbound and inbound email delivery, powerful spam filtering, and so, so much more.

your agent cluster-setup tab
Ask your agent to continue

Works with any framework or app


Email is our obsession.

PostShiba powers email behind the scenes at Bento. We've hand crafted every aspect of the service to ensure it meets the highest standards of deliverability and reliability.

This service runs on our own email technology and infrastructure which has allowed us to scale seamlessly. For the first time in Bento's history, we're able to share what we've built with companies that share similar values to us.

Your domains, one account

Add multiple sending domains without a per-domain charge. Verify each domain and share your cluster's sending capacity across them.

Add your first domain

Capacity you can budget for

Choose capacity for your busiest hour. See the monthly cluster price and what happens at the limit.

Estimate your price

Help when mail goes wrong

Inspect delivery events, configure the email firewall, and work with the team behind Bento to investigate sending problems.

How we handle incidents

Send and receive like a pro

1 <p>Hi Ana,</p>
2 <p>
3 Your account is ready. Sending is live on your
4 first domain, and a webhook is waiting for events.
5 </p>
6 <p>A few things to try first:</p>
7 <ul>
8 <li>Confirm DNS on your sending domain</li>
9 <li>Send a test to yourself</li>
10 <li>Watch the first delivered event</li>
11 </ul>
12 <p>
13 <a href="https://app.example.com/login">Sign in</a>
14 to open the dashboard.
15 </p>
16 <p>Welcome aboard,<br>The Example team</p>
Unique args Back on webhooks
1 {
2 "user_id": "usr_1024"
3 }
"; } function argsLine(value) { return Object.keys(value).map(function (key) { return key + " " + String(value[key]); }).join(" · "); } function phase() { return form.getAttribute("data-send-demo-phase") || "idle"; } function setPhase(next) { form.setAttribute("data-send-demo-phase", next); sendButton.disabled = next === "sending"; sendButton.textContent = PHASE_LABEL[next]; smtpPane.hidden = next === "idle"; } function stopSmtp() { if (smtpTimer) window.clearTimeout(smtpTimer); smtpTimer = 0; } function lineOk(text) { return /^(235|250|221)(\s|$)/.test(text); } function renderTranscript(lines) { smtpLog.replaceChildren(); lines.forEach(function (line) { var item = document.createElement("li"); item.setAttribute("data-side", line.side); if (line.side === "in" && lineOk(line.text)) item.setAttribute("data-ok", ""); item.textContent = line.text; smtpLog.appendChild(item); }); smtpPane.scrollTop = smtpPane.scrollHeight; } function firstBodyLine(html) { var line = String(html || "").split(/\r?\n/)[0] || ""; if (line.length > 72) return line.slice(0, 72) + "..."; return line; } function buildTranscript(state) { var parsed = parseArgs(state.uniqueArgs); var lines = [ {side: "in", text: "220 smtp.postshiba.com ESMTP"}, {side: "out", text: "EHLO local"}, {side: "in", text: "250-STARTTLS"}, {side: "in", text: "250 AUTH PLAIN"}, {side: "out", text: "STARTTLS"}, {side: "in", text: "220 Ready to start TLS"}, {side: "out", text: "EHLO local"}, {side: "in", text: "250 AUTH PLAIN"}, {side: "out", text: "AUTH PLAIN "}, {side: "in", text: "235 2.0.0 Authenticated"}, {side: "out", text: "MAIL FROM:<" + state.from + ">"}, {side: "in", text: "250 2.1.0 OK"}, {side: "out", text: "RCPT TO:<" + state.to + ">"}, {side: "in", text: "250 2.1.5 OK"}, {side: "out", text: "DATA"}, {side: "in", text: "354 End data with ."}, {side: "out", text: "From: " + state.from}, {side: "out", text: "To: " + state.to}, {side: "out", text: "Subject: " + state.subject} ]; if (parsed.ok) { lines.push({side: "out", text: "X-Capsule-Unique-Args: " + JSON.stringify(parsed.value)}); } lines.push({side: "out", text: firstBodyLine(state.html)}); lines.push( {side: "out", text: "."}, {side: "in", text: "250 2.0.0 Queued as capsule-44"}, {side: "out", text: "QUIT"}, {side: "in", text: "221 2.0.0 Bye"} ); return lines; } function reducedMotion() { return window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches; } function finishSmtp() { setPhase("sent"); smtpTimer = window.setTimeout(function () { smtpTimer = 0; if (phase() === "sent") setPhase("idle"); }, 900); } function revealSmtp(count) { renderTranscript(smtpLines.slice(0, count)); if (count >= smtpLines.length) { finishSmtp(); return; } smtpTimer = window.setTimeout(function () { revealSmtp(count + 1); }, 70); } function startSmtp() { if (phase() === "sending") return; stopSmtp(); smtpLines = buildTranscript(read()); setPhase("sending"); if (reducedMotion()) { renderTranscript(smtpLines); finishSmtp(); return; } revealSmtp(1); } function setView(view) { form.setAttribute("data-send-demo-view", view); codePane.hidden = view !== "code"; previewPane.hidden = view !== "preview"; viewButtons.forEach(function (button) { button.setAttribute("aria-selected", button.getAttribute("data-send-demo-view-btn") === view ? "true" : "false"); }); } function paint() { var state = read(); var parsed = parseArgs(state.uniqueArgs); var nextHtml = previewDocument(state.html); previewFrom.textContent = state.from; previewTo.textContent = state.to; previewSubject.textContent = state.subject; if (lastHtml !== nextHtml) { lastHtml = nextHtml; preview.srcdoc = nextHtml; } argsStatus.textContent = parsed.ok ? "Back on webhooks" : "Invalid JSON"; argsStatus.classList.toggle("is-invalid", !parsed.ok); previewArgs.hidden = !parsed.ok || !Object.keys(parsed.value).length; previewArgs.textContent = parsed.ok ? argsLine(parsed.value) : ""; } function schedule() { if (frame) return; frame = requestAnimationFrame(function () { frame = 0; paint(); }); } function watchValue(textarea) { var descriptor = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value"); Object.defineProperty(textarea, "value", { configurable: true, get: function () { return descriptor.get.call(this); }, set: function (next) { descriptor.set.call(this, next); schedule(); } }); } form.addEventListener("submit", function (event) { event.preventDefault(); }); form.addEventListener("input", schedule); form.addEventListener("keyup", schedule); form.addEventListener("paste", schedule); viewButtons.forEach(function (button) { button.addEventListener("click", function () { setView(button.getAttribute("data-send-demo-view-btn")); }); }); sendButton.addEventListener("click", startSmtp); form.querySelectorAll("[data-diffs-root]").forEach(function (node) { new MutationObserver(schedule).observe(node, {subtree: true, characterData: true, childList: true}); }); [htmlInput, argsInput].forEach(watchValue); setView(read().view); paint(); })();

Bring your app over with our provider-specific migration guide and SDKs. We've crafted our product to be easy to make the switch. You can even import your own DKIM keys.

Features

Track every message

Recent events

streaming
ana@example.com Delivered 2s ago
sam@example.org Processed 4s ago
ops@example.net Deferred 12s ago
old@example.com Bounced 31s ago
noreply@example.dev Dropped 48s ago
POST hooks.example.com/postshiba 200
1 [
2 {
3 "event": "delivered",
4 "email": "ana@example.com",
5 "sg_event_id": "capsule-44",
6 "order_id": "ord_4821",
7 "unique_args": {
8 "order_id": "ord_4821"
9 }
10 }
11 ]

Get detailed event logs and webhooks for every message. Inspect delivery responses and troubleshoot deferred, bounced, and dropped messages.

Features

Built for multi-tenant platforms

Name Slug Status
Umbrella umbrella warning sending off
Acme acme active
Globex globex active
Initech initech pending
Re: Order #4821 support+7f3a@inbound.acme.com
1 {
2 "to": "support+7f3a@inbound.acme.com",
3 "thread_id": "7f3a",
4 "from": "customer@example.com",
5 "subject": "Re: Order #4821",
6 "text": "Can I change the address?"
7 }

Customer isolation and control. We've built PostShiba to help you scale and police your email infrastructure with ease. Whether it's suspending individual senders or entire domains, we've got you covered.

Features

Plan your switch before moving production.

Start with one message type or customer. Scale up as you feel comfortable, we know how to make each migration as stress-free as possible.

Moving from Resend?

Map tags, attachments, template rendering, and event handlers. Check the idempotency and tracking differences before switching.

Read the Resend migration guide

Moving from Amazon SES?

Review your sending and receiving setup, then map the AWS pieces your application currently depends on.

Read the Amazon SES migration guide

Moving from SendGrid?

Check the supported sending fields, authentication, event signatures, and suppression import steps.

Read the SendGrid migration guide

Build email into your product

Before you start

A few things to know before bringing your first app to PostShiba.

Can I use multiple sending domains?

Yes. Add multiple sending domains to one account without a per-domain charge. Verify each domain before sending. Messages across those domains share your chosen cluster's capacity.

Set up a sending domain
What limits sending during beta?

Plan capacity is the sending limit during beta. Size your cluster for the busiest hour.

How do invitations and production approval work?

Join the waitlist for an invitation. After signup, create your first cluster, verify a domain, and test with your team's email addresses. Request production approval from the dashboard and tell us how you plan to use PostShiba.

We review accounts individually before opening sending to external recipients. There is no fixed invitation or approval timeframe during beta, so wait for approval before scheduling your migration.

How production approval works
Is there a trial, and do I need a card?

Your first cluster includes 7 days free. Add a payment method before creating it. The trial is tied to your first cluster's subscription and runs separately from production approval. The selected monthly plan applies after the trial.

Which plans can I start with?

New clusters can choose Nano (25 outbound emails/hour), Micro (150 outbound emails/hour), and Small (1,200 outbound emails/hour) during beta. Choose for your busiest hour, including spikes. If your workload needs more, contact us before moving production traffic.

Estimate your capacity plan
What happens during a traffic spike?

Requests over the hourly REST sending cap return 429 and are not queued by PostShiba. Your app must retain rejected messages and retry when capacity is available. Size your plan for peak traffic so urgent mail is not delayed.

Review sending and retry requirements
How do I get help?

Email jesse@postshiba.com for setup, migration, or sending questions. For a delivery investigation, include the message ID and sending domain. If you need specific support coverage, discuss it with us before migrating.

Ready to send?

Join the waitlist for an invitation. After signup, create a shared sending environment, verify your domain, and test with your team while we review production access.

See how production approval works before you join.

About

PostShiba is the email platform that powers Bento behind the scenes. You can build your own products, like Bento, on top of it.

© 2026 PostShiba by Backpack Internet Pty. Ltd. All rights reserved.

The same policies that govern Bento are applied to PostShiba Privacy | Terms | Security