Mailorbit

Self-hosted email marketing and newsletter SaaS. Your customers build lists, design emails with drag and drop, send campaigns and automations, and see every open and click. You run the platform, set the plans and get paid.

Version 1.0.0 · released 2026-10-16 · Next.js 16, React 19, TypeScript, Prisma 7 and PostgreSQL.

1. Welcome

Thank you for buying Mailorbit. This guide takes you from the download to a running email marketing platform on your own domain. You do not need to write code: you fill in a settings file, run one command, and finish the setup in your browser.

What is in the box

It works before you add any keys. The default sending server is Log only: every email lands in Admin → Outbox, where you can open it, and nothing leaves the server. Connect a real provider (SMTP, Amazon SES, Mailgun or Postmark) when you are ready to send.

Screenshots

Workspace dashboard
Workspace dashboard
Drag-and-drop email builder
Drag-and-drop email builder
Campaign wizard, review and schedule
Campaign wizard: review and schedule
Scheduled campaign with an A/B subject test
Scheduled campaign with an A/B subject test
Campaign report
Campaign report
Automation flow editor
Automation flow editor
Contacts
Contacts
Lists and segments
Lists and segments with a live count
Email templates
Email templates
Workspace reports
Workspace reports
Billing and usage
Billing and usage (your customer's view)
Landing page
Public landing page with your plans
Admin overview
Admin panel: overview
Admin workspaces
Admin panel: workspaces
Admin plans and quotas
Admin panel: plans and quotas
Admin branding
Admin panel: branding with live preview

2. Requirements

WhatVersionNotes
A server (VPS)1 GB memory, 1 CPU, 10 GB disk2 GB or more for large lists. Any Linux VPS (Ubuntu 24.04 recommended): Hetzner, DigitalOcean, Vultr, Linode, AWS Lightsail…
Docker with ComposeDocker 24+, Compose v2The recommended way. Installs PostgreSQL for you.
Or: Node.js and PostgreSQLNode.js 22+, pnpm 10+, PostgreSQL 14+For running without Docker (section 6).
A domain—For example mail.yourdomain.com for the app. Tracking links, signup forms and unsubscribe pages use it.
An email provider—Optional at first (Log only). For real sending: any SMTP service, Amazon SES, Mailgun or Postmark.
BrowserCurrent Chrome, Edge, Firefox or SafariFor you and your customers.

Third-party services

Mailorbit runs on your own server and needs no outside service to start. These optional services are run by other companies. Each provider has its own pricing and terms, and you pay them directly; nothing is included in the price of Mailorbit. Create your own account with each one you want to use.

ServiceUsed forNeeded?Where to sign up
Amazon SESSending email (low cost per thousand emails)Optional (one sending provider is needed to send real email)aws.amazon.com/ses
MailgunSending emailOptionalmailgun.com
PostmarkSending emailOptionalpostmarkapp.com
Any SMTP serviceSending email (Brevo, SendGrid, SMTP2GO, your host's mail server…)OptionalYour provider
StripeTaking card payments for your plansOptional (without it, plan changes use a demo payment)stripe.com
A VPS host and a domainRunning the appYes, for a public platformAny provider

Mailorbit does not load anything from a third-party server in the browser: fonts and icons are bundled.

3. Quick start (Docker)

This puts Mailorbit on your computer or server in about ten minutes. You need Docker (docs.docker.com/engine/install).

  1. Unzip the download and open the deploy folder in a terminal:
    cd mailorbit/deploy
    cp .env.example .env
  2. Open .env in a text editor and fill in three things:
    • POSTGRES_PASSWORD: a database password of your choice (letters and digits only).
    • APP_SECRET: a long random string. Make one with openssl rand -base64 32.
    • APP_URL: the address you will open, for example http://localhost:3000 on your computer or https://mail.yourdomain.com on a server.
  3. Start everything:
    docker compose up -d
    The first start builds the app (3–6 minutes). It then starts PostgreSQL, applies the database migrations, adds the base data (plans, starter templates, the Log only sender), and starts the web app and the worker.
  4. Open APP_URL in your browser. The install wizard opens (section 4).
Check that everything runs: docker compose ps shows postgres, web and worker as running (migrate exits after it finishes). Logs: docker compose logs -f web worker.

4. Install wizard and sample data

The first visit to your address opens /install. It has four steps:

  1. Server check: the database answers and migrations are applied, the worker runs, and APP_SECRET is long enough.
  2. Your platform: the platform name (shown everywhere, change it later in Branding), the system email address (password resets, invitations, confirmations) and the currency for plans.
  3. Admin account: your name, email and password. This is the platform admin.
  4. Sample data: a sample workspace (a plant shop with contacts, three sent campaigns with reports, automations and signup forms) so every screen is filled in. Leave it on to explore; delete it later in Admin → Workspaces → Manage → Delete.

After the wizard you land in the admin panel. The wizard closes itself once an admin exists; it cannot be run again.

5. Put it online (VPS, HTTPS)

Option A: the bundled HTTPS (simplest)

  1. Point your domain at the server: create an A record for mail.yourdomain.com with the server's IP address at your DNS provider.
  2. In deploy/.env set DOMAIN=mail.yourdomain.com and APP_URL=https://mail.yourdomain.com.
  3. Make sure ports 80 and 443 are free and open in the firewall, then run:
    docker compose --profile https up -d
    Caddy gets and renews a free Let's Encrypt certificate on its own.

Option B: your own reverse proxy

If the server already runs nginx, Traefik or Caddy, keep WEB_PORT (default 3000) and proxy your domain to http://127.0.0.1:3000. Example for nginx:

server {
  server_name mail.yourdomain.com;
  location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    client_max_body_size 20m;
  }
}
Set APP_URL to the public https address before you send real email. Every tracking link, image, signup form and unsubscribe link in your emails is built from it.

Backups

Everything lives in two Docker volumes: postgres-data (the database) and uploads (images used in emails and logos). Back up the database every night, for example:

docker compose exec -T postgres pg_dump -U mailorbit mailorbit | gzip > mailorbit-$(date +%F).sql.gz

6. Without Docker

Mailorbit is a standard Next.js app plus a worker process. You can run it on any host that keeps a Node.js process running (a VPS with PM2 or systemd, Railway, Render, Fly.io…).

  1. Create a PostgreSQL 14+ database.
  2. In the web folder: cp .env.example .env and fill in DATABASE_URL, APP_URL and APP_SECRET.
  3. Install, migrate and build:
    pnpm install
    pnpm prisma:migrate:deploy
    pnpm prisma:seed -- --base
    pnpm build
  4. Run two processes and keep both running:
    pnpm start      # the web app (port 3000; set PORT to change it)
    pnpm worker     # sending, schedules, automations, imports
Serverless hosts that only run code during a web request (for example plain Vercel functions) cannot run the worker. Host the worker on a small server or a background-worker service, pointed at the same database.

7. Sending email

Email leaves Mailorbit through sending servers. There are two kinds:

Providers

ProviderWhat to fill inWhere to find it
Log onlyNothingThe default. Emails go to Admin → Outbox and the worker log; nothing is sent.
SMTPHost, port (587 with STARTTLS or 465 with SSL), username, passwordYour email provider's SMTP settings page.
Amazon SESAWS region, access key ID, secret access key, configuration set (optional)AWS console → IAM: create a user with the ses:SendEmail and ses:SendRawEmail permissions and an access key. Verify your domain in SES and request production access (new accounts start in the sandbox).
MailgunSending domain, region (US or EU), API keyMailgun → Sending → Domains, and API Security for the key.
PostmarkServer API token, message stream (use a broadcast stream for newsletters)Postmark → your server → API Tokens.

Each server has a rate limit (emails per second). The worker never sends faster than that, so you stay inside your provider's limits. Use Test on a server to send a test email before you make it the default.

Provider passwords and keys are stored encrypted with APP_SECRET. They are never shown again after you save them.

Domain records (SPF, DKIM, DMARC)

Inbox providers trust email from a domain that proves it allowed the sender. For the domain in your From address, add the records your provider gives you:

Every campaign email already carries an unsubscribe link, a List-Unsubscribe header with one-click unsubscribe (required by Gmail and Yahoo for bulk senders), and the workspace's postal address in the footer.

Bounces and complaints

When an address does not exist or someone marks an email as spam, the provider can tell Mailorbit, which then stops emailing that contact. The webhook addresses are shown on the Sending pages (Admin → Sending servers for platform servers, App → Sending for a workspace's own servers). Copy them into your provider:

Set WEBHOOK_KEY in .env to protect these addresses; the key is already part of the address shown on the Sending pages.

A hard bounce marks the contact as bounced; a complaint marks it complained and unsubscribes it. Neither is ever emailed again by campaigns or automations.

8. Payments (Stripe)

Without Stripe keys, customers change plans with a demo payment (no card), which is useful while you test. To take real payments:

  1. In the Stripe dashboard, copy your secret key (dashboard.stripe.com/apikeys) into STRIPE_SECRET_KEY.
  2. Developers → Webhooks → Add endpoint: https://mail.yourdomain.com/api/stripe/webhook with the events checkout.session.completed, invoice.paid and customer.subscription.deleted. Copy its signing secret into STRIPE_WEBHOOK_SECRET.
  3. Restart: docker compose up -d.

Plans are monthly subscriptions. Mailorbit creates the price in Stripe Checkout from the plan's price, or uses a Stripe price ID if you enter one on the plan (Admin → Plans). Customers manage their card and invoices in the Stripe customer portal from Billing. Turn on the customer portal once in Stripe: Settings → Billing → Customer portal.

Charging your own customers for plans makes Mailorbit an end product that users pay for, which needs the Envato Extended Licence (section 20).

9. Using Mailorbit

This section is also a guide you can share with your customers.

Contacts

Add contacts by hand, import a CSV, or collect them with signup forms. Each contact has a status (subscribed, unconfirmed, unsubscribed, bounced or complained), lists, tags, custom fields, notes and an activity history. Only subscribed contacts receive campaigns and automations.

Import a CSV

Contacts → Import CSV: upload a file with a header row, match each column to a field (email, first name, last name or a custom field), choose lists and tags, and start. The worker imports in the background; invalid and duplicate rows are skipped and counted. Existing contacts are updated, never re-subscribed if they unsubscribed.

Lists and segments

A list is a group people join (a newsletter, customers, a waitlist). A segment is a saved filter with rules on fields, tags, lists, dates, engagement (opened or clicked in the last N days) and campaigns (received, opened, did not open, clicked). The count updates while you edit the rules. Send a campaign to a list, a segment, or a list narrowed by a segment.

Signup forms

Signup forms → New form: pick the list and tags, the fields, the texts and the colour, and turn on double opt-in if you want new people to confirm by email first. Put the form on any website in one of three ways:

Every form has a hidden spam trap and an optional consent checkbox. Views and signups are counted.

Templates and the email builder

Templates → New template, or the Content step of a campaign, opens the builder. Drag blocks from the left into the email (or click a block to add it): hero, heading, text, image, button, columns, product, divider, spacer, social links and HTML. Click a block to edit it on the right; use the toolbar to move, duplicate or delete it. The Style tab sets the colours, fonts and width; the Templates tab starts again from a template. Preview shows desktop and mobile. Undo and redo work with Cmd/Ctrl+Z and Shift+Cmd/Ctrl+Z.

Merge tags put contact data into the email: {{first_name}}, {{last_name}}, {{email}} and custom fields. Add a fallback after a bar: {{first_name|there}}. The footer with the unsubscribe link and the postal address is added to every campaign email automatically.

Campaigns

  1. Recipients: lists, a segment, and a segment to leave out. The live count shows who will get it; nobody gets it twice.
  2. Content: the email builder.
  3. Subject and A/B test: the subject, the preview text and the sender. Turn on the A/B test to try a second subject on a test group (for example 20%); after the waiting time the subject with the better open or click rate goes to everyone else.
  4. Review and schedule: a pre-flight check (subject, links, alt text, address, enough emails left this month), then Send now or Schedule in the workspace's time zone.

While it sends, the report fills in: delivered, opens, clicks, unsubscribes, bounces, the A/B result, top links and email clients. Pause, resume or cancel any time. Resend to non-openers makes a copy for the people who did not open. Export the report as CSV.

About open rates: some email apps (Apple Mail with Mail Privacy Protection) load every image, which counts as an open. Reports show those opens apart so you can judge real interest by clicks.

Automations

Automations → New automation (or start from the welcome series preset). Choose a trigger: a contact joins a list, a tag is added, someone fills in a form, or you start it from a contact's page. Add steps from the left or with the + between steps: send email, wait, if/else (opened or clicked the last email, has a tag, is in a list), add or remove a tag, add to a list, or call a webhook. Save, then turn it on. Each contact goes through a flow once. The numbers on each step show who is waiting there and how its emails perform. Test with a contact runs the flow for one address.

Reports

Reports shows the last 30 days for the workspace: emails sent, opens, clicks, new subscribers and unsubscribes per day, recent campaigns, lists and automations.

Team

Team → Invite someone sends an email invitation. Roles: owner (everything, including billing and deleting the workspace), admin (manages the team, sending servers and settings), editor (builds and sends: contacts, forms, templates, campaigns, automations) and viewer (reads everything, changes nothing). The plan sets how many seats a workspace has.

10. Running the platform

11. Rebrand: logo, colours, fonts

Admin → Branding changes the whole platform (landing page, app, admin, signup forms and system emails) without touching code: platform name, logo for light and dark backgrounds, favicon, brand colour, heading and body fonts (Sora, Figtree, Inter or DM Sans, all bundled), support email and the badge text in email footers (shown on plans that keep the badge). The preview on the right shows the result before you save. Reset to default goes back to the original look.

The landing page text lives in web/src/app/page.tsx if you want to rewrite it (section 14).

12. Setup check

Admin → Setup lists every service with its state: Working, Check (it works, but on a safe fallback such as Log only or demo payments), Optional (not set) or Needs action. The Test buttons check each connection, and Send a test email sends through the platform's default server. The same check runs in a terminal:

# with Docker, in the deploy folder:
docker compose exec worker pnpm setup:check
# without Docker, in the web folder:
pnpm setup:check

pnpm setup:check lists missing keys and tests the database, the worker, the default sender and Stripe; it exits with an error when something required is missing.

13. Every key, explained

Keys go in deploy/.env (Docker) or web/.env (without Docker). Docker keys are read by Docker Compose only. After a change, run docker compose up -d again.

KeyRequiredWhereWhat it does
Core
DATABASE_URLYesAppPostgreSQL connection URL. The Docker stack builds it from the POSTGRES_* keys for you.
APP_URLYesAppPublic address of your platform, no trailing slash. Tracking links, signup forms and unsubscribe links use it.
APP_SECRETYesAppA long random string (32+ characters). Signs sessions and links and encrypts sending-server keys. Never change it after setup.
Docker
POSTGRES_DBYesDockerDatabase name the Docker stack creates.
POSTGRES_USERYesDockerDatabase user the Docker stack creates.
POSTGRES_PASSWORDYesDockerDatabase password. Letters and digits only (it goes into a URL).
WEB_PORT—DockerHost port for the web app (default 3000).
DOMAIN—DockerYour domain for automatic HTTPS with the bundled Caddy (--profile https).
Payments
STRIPE_SECRET_KEY—AppStripe secret key (dashboard.stripe.com/apikeys). Empty = plan changes use the demo payment.
STRIPE_WEBHOOK_SECRET—AppSigning secret of the Stripe webhook that points at <APP_URL>/api/stripe/webhook.
Sending
WEBHOOK_KEY—AppShared key for bounce webhooks: add ?key=<value> to the webhook URLs you give SES, Mailgun and Postmark.
Storage
UPLOAD_DIR—AppFolder for uploaded images (default ./uploads; the Docker stack uses a volume).
Worker
WORKER_INTERVAL_MS—AppHow often the worker looks for work, in milliseconds (default 2000).
LOG_EMAILS—AppSet to false to stop the Log-only sender printing each email to the console.
Demo
DEMO_MODE—AppLeave empty. "true" turns on the public-demo mode: one-click demo logins, nothing is ever sent, nightly reset.
Never change APP_SECRET after setup: it encrypts the saved sending-server passwords and signs every unsubscribe and tracking link already sent.

14. Customising the code

You do not need to change code to run Mailorbit. If you want to, the project is plain Next.js App Router with TypeScript:

After changing code, rebuild the containers: docker compose up -d --build.

15. File structure

mailorbit/
├── CHANGELOG.md
├── LICENSE.txt
├── deploy/                    Docker Compose stack (copy .env.example to .env)
│   ├── docker-compose.yml
│   └── .env.example
├── docs/                      this guide (HTML and PDF)
└── web/                       the app, admin, public pages, API and worker
    ├── Dockerfile
    ├── .env.example           for running without Docker
    ├── public/                favicon
    ├── e2e/                   browser smoke tests (Playwright)
    └── src/
        ├── app/               pages: / (landing), /app (workspace), /admin, /install, /f (forms), /t (tracking), /u (unsubscribe), /api
        ├── components/        shared UI, the email builder, charts
        ├── database/          Prisma schema, migrations, seed data
        ├── lib/               email rendering, segments, automation steps, time zones
        │   └── server/        sending, campaigns, automations, tracking, imports, payments, settings, setup check
        ├── scripts/           setup check in the terminal
        ├── tests/             test helpers
        └── worker/            the background worker

16. Development and tests

cd web
cp .env.example .env          # point DATABASE_URL at a local PostgreSQL
pnpm install
pnpm prisma:migrate:deploy
pnpm prisma:seed -- --base
pnpm dev                      # http://localhost:3481
pnpm worker                   # in a second terminal
CommandWhat it does
pnpm lintBiome lint and format check
pnpm typecheckTypeScript check
pnpm testUnit and database tests (Vitest). Each run uses a throwaway schema in DATABASE_URL's database and drops it afterwards.
pnpm e2eBrowser smoke tests against a running server (E2E_BASE_URL, default http://localhost:3481). Run npx playwright install chromium once first.
pnpm setup:checkSetup check in the terminal

17. Updating

  1. Back up the database (section 5).
  2. Download the new version from CodeCanyon and unzip it next to the old one.
  3. Copy your deploy/.env into the new deploy folder. If you changed code, carry your changes over.
  4. In the new deploy folder run docker compose up -d --build. Migrations run on their own; your data stays in the Docker volumes.

Keep the same Compose project name (the folder name deploy, or name: mailorbit in the compose file) so Docker reuses the same volumes.

18. FAQ and troubleshooting

The page shows "Install" again, or the wizard does not open

The wizard appears only while there is no admin. If it does not open, check that migrate finished: docker compose logs migrate.

Emails do not arrive

Open Admin → Setup. If the default sender is Log only, the emails are in Admin → Outbox, not in inboxes. Otherwise use Test on the sending server and read the error. Check that the worker runs (docker compose ps; Setup shows "Worker: Working").

A campaign stays "Sending" or "Paused"

Paused campaigns show the reason at the top, for example "Needs 12,000 emails, 3,000 left this month". Raise the plan's allowance, reset it in Admin → Workspaces, or upgrade the workspace, then press Resume.

Opens and clicks are not counted

APP_URL must be the public address people can reach. Links in emails sent while it was http://localhost:3000 cannot be tracked.

Amazon SES says "Email address is not verified"

Your SES account is in the sandbox. Verify the sending domain and request production access in the SES console.

Port 3000 is already in use

Set WEB_PORT=3001 (or any free port) in deploy/.env and run docker compose up -d again.

How do I remove the sample data?

Admin → Workspaces → the sample workspace → Manage → Delete. Your own workspaces are not touched.

How do I make someone else a platform admin?

Admin → Users → the person → Make admin.

19. Credits

Mailorbit is built on open-source software. Thank you to their authors.

PackageLicenceLink
Next.js, ReactMITnextjs.org, react.dev
Prisma, @prisma/adapter-pg, pgApache 2.0, MITprisma.io
Tailwind CSSMITtailwindcss.com
Lucide icons (lucide-react)ISClucide.dev
NodemailerMIT-0nodemailer.com
AWS SDK for JavaScript (SES v2)Apache 2.0github.com/aws/aws-sdk-js-v3
Stripe Node.js libraryMITgithub.com/stripe/stripe-node
Papa ParseMITpapaparse.com
ZodMITzod.dev
next-themes, sonner, clsx, tailwind-merge, dotenv, tsxMITnpmjs.com
Sora, Figtree, Inter, DM Sans fonts (via Fontsource)SIL Open Font License 1.1fontsource.org
Biome, Vitest, Playwright, TypeScript (development only)MIT, Apache 2.0biomejs.dev

The sample workspace "Bloom & Root", its contacts, emails and texts are invented for the demo. No photos are bundled.

20. Licence

Mailorbit is sold under the Envato Market licences (codecanyon.net/licenses/standard):

One licence covers one platform on one domain. See LICENSE.txt for details.

21. Changelog

1.0.0 — 2026-10-16

22. Support

Questions or problems? Use the Support tab on the item's CodeCanyon page. Please include your Mailorbit version, how you host it (Docker or not), and what Admin → Setup shows. Support covers installing, configuring and bugs; custom changes are not included.

Thank you for choosing Mailorbit.