EmailOctopus

emailoctopus.comcontributed by Samuele Ongaro

ALMOST

A weekend of work, and real gaps remain.

Email marketing at a low price, historically by sending through Amazon SES on your behalf. Lists, campaigns, simple automations and landing pages.

Promptfree, for everyone, and the only version there is
Build me email marketing that replaces EmailOctopus — and know exactly what the price is buying.

It is **the SES relationship, wrapped so you never touch it**: the quota increases, the account review that comes with volume, the suppression list, and the bounce plumbing. You will still send through a provider. What you take on is the account, the warm-up, and being the one who is suspended if the complaint rate rises. That is the whole verdict.

STACK
- Node 20+ with Fastify, server-rendered HTML
- SQLite through better-sqlite3, WAL mode
- Amazon SES or an equivalent, through its API
- A worker for sending, separate from the web process
- Caddy in front

THE SES REALITY, BEFORE ANY CODE
- A new account is in a sandbox: you can only send to verified addresses, at a low rate, until you request production access and explain what you send and how people opted in. That request is a form a human reads, and it can be refused
- Quota increases are requested as volume grows, each one a wait
- The account is suspended if the bounce rate or complaint rate crosses a threshold. Those thresholds are low and they are measured over a rolling window
- So: read the sending policy before writing anything, and put the numbers in the README

THE DATA MODEL
- lists, contacts, segments — segments as saved rules evaluated at send time, never stored as a member list
- contacts: id, list_id, email, fields_json, status, confirmed_at, unsubscribed_at, bounced_at, complained_at, source, consent_text, consent_at, ip_hash
- campaigns: id, list_id, segment_id, subject, preheader, body_html, body_text, status, scheduled_for, sent_at, recipient_count
- deliveries: id, campaign_id, contact_id, status, sent_at, opened_at, bounced_at, bounce_kind, complained_at — one row per person per campaign, written before sending, which makes a resume exact and a duplicate impossible
- suppression: email_hash, reason, at — global, across every list, forever
- automations and automation_sends, so nobody receives a step twice
- provider_events: id, message_id, kind, payload_json, processed_at — bounces and complaints arrive as notifications and must be idempotent

SENDING
- The worker claims a batch with a lease, sends, records the provider's message id, and continues. A crash resumes exactly where it stopped
- Rate limited to the account's current quota, read from the provider rather than hard-coded
- A test send required before any campaign, and a confirmation showing the recipient count and the segment
- Bounces and complaints consumed from the notification topic: a hard bounce suppresses immediately, a soft bounce counts and suppresses after several, a complaint suppresses permanently and is never mailed again under any circumstance
- The provider's own suppression list synchronised with yours, so the two never disagree

DELIVERABILITY
- SPF, DKIM and DMARC on your sending subdomain, with the records in the README
- Separate subdomains for marketing and transactional. A password reset that fails because a campaign got complaints is a support disaster
- Warm slowly: hundreds, then doubling over weeks
- List hygiene: suppress anyone who has not opened anything in a very long time, and say so in the interface

THE MESSAGE
- Built with MJML or tables and inline styles, with a plain-text alternative generated from the same source
- Preview at phone and desktop width, and in the client that renders with the Word engine — that one is the constraint
- Personalisation with a default for a missing value
- One-click unsubscribe with no login, plus the List-Unsubscribe headers the large providers now effectively require

THE LIST
- Double opt-in, a signup form and an embeddable one, honeypot, rate limit per address hash
- The consent sentence stored with its timestamp exactly as shown
- Import with a dry run and a declaration of where the addresses came from. Importing a purchased list is how an account is closed in a week

OPERATIONS
- .env: DATABASE_PATH, BASE_URL, AWS credentials and region, FROM_ADDRESS, SESSION_SECRET, HASH_SALT
- Migrations on boot, each once; nightly backup off the machine — the list is the asset
- Health endpoint reporting quota, send rate, bounce rate and complaint rate. Those last two are the numbers to watch daily

WHAT MATTERS MOST
Suppression and the complaint rate. Wire the notifications before the first campaign, because reputation is the one thing here that cannot be repaired afterwards.

What you lose

  • The whole SES relationship — quota increases, suppression lists and the account review that comes with sending volume
  • A drag-and-drop editor and templates that render correctly in Outlook, which is its own discipline
  • Automation sequences with timing and conditions already built

If you would rather not build

  • Amazon SES on its own, for transactional mail

What it costs

as published on their pricing page

PlanBilled monthlyBilled yearlyLast read
—$9/mo——

Their pricing page is where these came from. Seeing a different price? Tell us.

The escape hatch

open source · no votes, no paid placement

Listmonk

$0

Self-hosted campaign email that speaks SMTP or SES directly.

knadh/listmonkfree · open source

MJML

$0

A markup language that compiles to email HTML which survives Outlook.

mjmlio/mjmlfree · open source

Why this verdict

our own opinion · changed only by a person

56/100

Verdict kinda at 56: sending is a solved problem via SES, but Outlook-safe templates and sequence timing are where the weekend goes.

History

tracked since 10 Aug 2026 · nothing is ever overwritten

Interest · last 30 dayspeak 2/day
views01230 Aug4 Sept9 Sept14 Sept19 Sept24 Sept28 Sept
— views— prompt copies none yet— votes none yet

Questions about EmailOctopus

answered from the record above

Is EmailOctopus free?

No — the plan we track is $9 a month. Starter at $9/month billed monthly for 500 subscribers; free up to 2,500 with limited sends.

Can you replace EmailOctopus by building your own?

ALMOST. A weekend of work, and real gaps remain. Replacement score 56 out of 100, build time a weekend. Read what you lose before you decide.

How much does EmailOctopus cost?

$9 a month on Starter — $108 a year. Recorded 9 Aug 2026.

What do you lose by replacing EmailOctopus?

The whole SES relationship — quota increases, suppression lists and the account review that comes with sending volume; A drag-and-drop editor and templates that render correctly in Outlook, which is its own discipline; Automation sequences with timing and conditions already built. If any of those carry weight for you, keep paying.

Is there an open-source alternative to EmailOctopus?

Yes: Listmonk, MJML. The prompt on this page is for when you want it your way instead.

Related entries

same category first, most replaced first

All 33 in Email & newsletters

Not sending yet

Every week, something stops being worth paying for.

New verdicts, prices that moved, entries added. One email a week. Unsubscribe in one click. Nothing is being sent yet — your address is kept here, and the first issue is the first thing it is used for.

free forever · no tracking pixel · stored here, never passed to anyone

Esc