What this is for#
AcelleMail can be operated as a multi-tenant SaaS — each customer signs up, picks a plan, pays via Stripe, and gets an isolated workspace (lists, campaigns, automations, sending quotas, even their own sending domain). The operator (you) collects subscription revenue, manages the underlying infrastructure, and keeps the margin.
This guide walks the end-to-end setup. Before you start, decide whether SaaS is actually the right model — see the Building Your Email Marketing SaaS sibling article for the pricing + GTM playbook.
Prerequisites:
- An AcelleMail Extended License from CodeCanyon. The Regular License does not allow you to resell access to the platform — the Extended License is required for any SaaS use case.
- A live AcelleMail install — see the canonical Ubuntu 24.04 guide. At SaaS scale, target Medium tier (4 vCPU, 8 GB) minimum.
- A Stripe account (the only first-class subscription gateway in current Acelle Cashier — see the FAQ for why PayPal isn't recommended).
- A sending relay configured (Amazon SES is the typical choice; you can also let customers BYO their own SES/Mailgun/SendGrid).
Step 1 — Enable customer signups#
By default, AcelleMail is single-tenant — only admins can create accounts. For SaaS, you flip this in Admin → Settings → General → User Signup:
- Enable user signup: Yes
- Email confirmation required: Yes (essential — without it spammers will sign up to use your sending IPs)
- Default plan after signup: the free / trial plan you'll create in Step 3
- Welcome email template: pick or create one that sets customer expectations + links to your docs
The public /register route is now live. Customers who hit it will see your branded signup form (configured per the white-label guide).
Step 2 — Configure Stripe as your payment gateway#
In Admin → Payment Gateways → Stripe → Edit:
| Field |
Where it comes from |
| Publishable Key |
Stripe Dashboard → Developers → API keys → pk_live_... |
| Secret Key |
Stripe Dashboard → Developers → API keys → sk_live_... |
| Webhook Signing Secret |
Set up the webhook first (next paragraph), then paste the whsec_... from Stripe |
| Mode |
live (use test for staging) |
| Currency |
The Stripe-account default; must match plan currencies |
Set up the Stripe webhook — required for renewals, cancellations, and dunning to work:
- URL:
https://your-domain.com/stripe/webhook (the URL is shown in your AcelleMail's Stripe gateway page after you save)
- Events to send:
customer.subscription.created, customer.subscription.updated, customer.subscription.deleted, invoice.paid, invoice.payment_failed, payment_intent.succeeded
Test mode first. Use the Stripe test keys + test webhook on a staging install before flipping to live mode. A wrong webhook in production means missed renewals and angry customers.
Click Enable on the gateway. Disable any other gateways you're not using (Admin → Payment Gateways → toggle the rest off) — leaving inactive ones enabled shows confusing options to your customers at checkout.
Step 3 — Design plans#
In Admin → Plans → Add new. Each plan controls what a customer can do, and the price they pay for it.
The Plan form has these fields (per the plans table schema):
| Field |
What it sets |
| Name |
Plan display name on your pricing page |
| Description |
Markdown allowed; shows under the plan card |
| Price |
Decimal; the subscription amount per frequency |
| Currency |
Must match your Stripe account currency |
| Frequency amount + unit |
e.g. 1 + month for monthly; 1 + year for annual |
| Trial amount + unit |
e.g. 14 + day for a 14-day free trial; leave blank for no trial |
| Status |
Active / Inactive |
| Visible |
If false, plan exists but doesn't show on the public pricing page (use for grandfathered or hidden plans) |
| Own tracking domain required |
Forces each customer on this plan to set up their own tracking subdomain (recommended for higher tiers to protect your shared domain's reputation) |
| Options (JSON) |
The quota / feature flags — see below |
The Options field is a JSON blob stored on the plan. This is where the per-plan quotas live:
{
"max_subscribers": 5000,
"max_lists": 10,
"max_campaigns": -1,
"max_emails_per_month": 50000,
"max_subscribers_per_list": 5000,
"max_segments_per_list": 10,
"max_automations": 3,
"max_templates": -1,
"max_sending_servers": -1,
"max_email_verification_servers": -1,
"max_team_members": 2,
"api_access": true,
"create_sending_server_enabled": false,
"automation_enabled": true,
"custom_domain_enabled": false,
"custom_html_enabled": false
}
Use -1 for "unlimited" on numeric quotas. true/false for feature toggles. The admin UI exposes these as labelled form fields, so you usually don't hand-edit JSON — but knowing the underlying shape helps when scripting plan creation.
Attach sending servers + email verification servers to the plan (via the Plan edit page → Sending Servers tab). A plan with no sending servers attached means the customer must BYO — set create_sending_server_enabled: true in that case so they can add their own SES/Mailgun creds.
Pricing-tier recipe (use as starting point)#
Three-tier ladder that works for most B2B SaaS positionings:
| Tier |
Price |
Subscribers |
Sends/mo |
Automations |
Custom domain |
Notes |
| Starter |
$19/mo |
2,500 |
25,000 |
3 |
No |
Self-serve credit-card signup |
| Pro |
$79/mo |
15,000 |
150,000 |
Unlimited |
Yes |
Most popular; the "anchor" tier |
| Agency |
$199/mo |
50,000 |
500,000 |
Unlimited |
Yes + sub-accounts |
Sales-assisted; 14-day trial |
Add an annual variant of each plan at ~17% discount (10 months for the price of 12) — this is the standard SaaS lever and meaningfully reduces churn.
For sizing the underlying server, see Server Requirements. 100 Pro-tier customers (≈15M sends/month aggregate) is the Medium tier; 500 is the Large tier.
Step 4 — Customer onboarding flow#
What a new customer experiences end-to-end:
- Lands on your pricing page → clicks Get Started on a plan
- Hits your AcelleMail
/register → fills email + password
- Confirms email via the link AcelleMail sends
- Logs in → lands on the welcome screen
- AcelleMail Cashier prompts for payment (unless the plan is free or has a trial) → Stripe Checkout
- On successful payment, the customer is auto-subscribed to the plan, and their tenant workspace is ready
You should customise the welcome flow:
- Welcome email template (
Admin → System Emails → Welcome) — set tone, link to your getting-started docs, embed a YouTube walkthrough
- First-login flow — Acelle shows a generic empty dashboard. Consider linking from your welcome email directly to "Step 1: import your first list" rather than the dashboard
- In-app tour — Acelle ships no in-app tour. For an upmarket SaaS, consider adding an Intercom / Userpilot overlay via your custom CSS/JS (see white-label guide)
Step 5 — Tenant isolation#
Each AcelleMail customer is a separate tenant with their own:
- Subscriber lists + segments
- Campaigns + templates
- Automation workflows
- Sending quotas (enforced per-plan via the
options JSON quotas)
- Sending server attachments (per plan)
- API key (each customer generates their own under their profile)
- Optional: their own sending domain + tracking domain
What's NOT isolated (important to know):
- The underlying database is single-database — all tenant data is in the same
acelle MySQL database, scoped by customer_id on each row. This is fine for legitimate SaaS, but means a database-level compromise affects all tenants.
- Storage paths are also shared (
storage/uploads/<customer_id>/...) — same shared-file-system caveat.
- Sending IPs are shared by default — unless a customer is on a plan that requires "Own sending server" + has their own SES configured, they share your shared IP pool. One bad-actor customer can degrade reputation for everyone — see the FAQ for mitigations.
Step 6 — Day-2 operations#
After the system is live, the recurring operational tasks:
- Monitor signups for spam. Spammers will sign up to use your free trial / shared sending pool. Watch the
email_log table for unusual sending patterns; consider requiring credit-card-on-file even for free trials.
- Reconcile Stripe ↔ AcelleMail subscriptions. The webhooks are reliable but not perfect — once a week, spot-check that Stripe's active subscription count matches AcelleMail's. Acelle ships a reconcile job (see
acelle:remote-subscriptions:reconcile in php artisan list).
- Sending quota enforcement. AcelleMail enforces
max_emails_per_month at send time — a customer hitting their cap will see "You have exceeded your sending quota". They have to either wait until the next cycle or upgrade their plan.
- Customer support tickets. Most common: bounce-handling failures (the customer's SES setup), authentication issues, "where do I add SPF/DKIM" (link them to your guide). Stand up a help-desk early.
- Plan migrations. When you change a plan's price or limits, existing subscribers stay on their old terms unless you explicitly migrate them. Acelle's admin UI has a Plan → Migrate flow.
Step 7 — White-labelling#
If you're running this under your own brand (not "Powered by AcelleMail"), follow the white-label customization guide. The Extended License explicitly allows full re-branding.
Common issues#
| What you see |
Likely cause |
Fix |
| Stripe charge succeeds but customer plan not updated in AcelleMail |
Webhook not configured or signing secret wrong |
Re-create the webhook in Stripe Dashboard; paste the whsec_... into AcelleMail's Stripe gateway settings |
| Customer can't add their own SES — "feature not enabled" |
Plan's options.create_sending_server_enabled is false |
Edit the plan; toggle Allow custom sending server: Yes |
| Customer sends are counted against an old plan after upgrade |
Plan migration wasn't propagated |
Run php artisan acelle:remote-subscriptions:reconcile or use Admin → Subscriptions → Sync |
| Customers complain about deliverability after a spam-blast tenant |
Shared-IP pool reputation hit |
Move legitimate customers to a dedicated sending server; suspend the bad-actor tenant |
| Trial customers never convert |
No automation, no email reminders |
Set up a 3-step trial-conversion automation targeting customers near trial expiry |
| Free-tier customers send to spam-trap lists |
No list-hygiene policy enforced |
Require double opt-in on free tier (require_confirmation_on_signup per plan), or run a list-hygiene check at signup |
FAQ#
Why is PayPal not a first-class option anymore? Acelle Cashier (the subscription billing layer) consolidated on Stripe + Offline in the recent refactor. PayPal recurring subscriptions are operationally messier (no webhook for failed payments, no first-class trial support, currency conversion overhead) and the maintenance burden didn't justify keeping it. If you need PayPal, run it as "Offline" mode with manual reconciliation, or set up a separate Stripe → PayPal Express Checkout integration.
Can I migrate from PayPal to Stripe? Yes — existing PayPal subscriptions stay until they next renew, at which point they'll need to re-enter payment via Stripe. Communicate this to customers in advance via a 30-day notice email.
Can I run as a hybrid (some self-hosted, some SaaS)? Yes. Disable user signup (Step 1) for the self-hosted tier; only your team creates those customer accounts. Use plans for both, just hide non-public plans (visible: false).
How do I bill customers in multiple currencies? Each plan has a single currency. Create parallel plans in each currency (e.g. "Pro $79" and "Pro €72"). Customer's billing currency is locked to the plan they signed up on; you can't auto-convert.
Can a customer have multiple subscriptions? Yes — Acelle's data model supports it (a customer can have multiple active subscriptions to different plans, e.g. a "Sending credit" add-on alongside a base plan). The UI for end-customers shows them their primary plan plus any add-on subscriptions.
Can I require credit card on file for free trials? Set require_payment_method_on_trial: true in the plan options. Customers hit Stripe's payment method capture flow before the trial starts. Significantly reduces signup fraud.
Does AcelleMail send abandoned-checkout emails? No — that's outside Acelle's scope (it's not an e-commerce platform). Integrate via your own marketing-automation tool (HubSpot, Customer.io, ActiveCampaign), or write a custom Laravel listener on the SubscriptionAbandoned event.
What happens when a subscription is cancelled? Per Stripe's webhook, AcelleMail flips the subscription status to cancelled and downgrades the customer to the default free plan (or suspends if there's no free plan). Existing campaigns / lists / templates are retained; only sending is blocked.
GDPR / right-to-erasure? When a customer requests deletion, Admin → Customers → ... → Delete removes the customer record and all their related data (lists, subscribers, campaigns, automations). Sending logs may be retained per your retention policy — document this in your privacy policy.
Related articles#