MailTidy3
MailTidy3 · Documentation

Email verification,
done right.

A complete guide to installing, configuring, and operating MailTidy3 — the self-hosted email verification platform that is 18× faster than the original MailTidy, with a public API, multi-worker scaling, and honest results.

18×
Faster than legacy MailTidy
0.28s
Per-email verification
150K
Emails/day on 1 VPS
9
Classification types
01 · Overview

What is MailTidy3?

MailTidy3 is a self-hosted email list verification SaaS you install on your own VPS. You own the server, the data, and the throughput.

Unlike cloud-based verifiers that charge per email and throttle your throughput, MailTidy3 runs entirely on infrastructure you control. Upload a list of 100,000 emails, get accurate classifications back — valid, invalid, catch-all, disposable, role-based — without per-email fees.

The system is built on three components: a Laravel 13 web application handling auth, billing, and the buyer dashboard; a Python FastAPI verification engine doing the actual SMTP probing; and lightweight worker agents you can deploy to additional VPS to multiply throughput.

18× faster engine
Async Python + asyncio replaces the old sequential PHP engine. 0.28s per email vs 3–5s.
🔌
Public REST API
Verify single emails or bulk lists programmatically. API keys with per-day quotas.
📡
Multi-worker scaling
Add worker VPS with one command. Each worker = one IP = independent rate-limit budget.
🏷️
9 classification types
Valid, invalid, catch-all, disposable, role-based, no MX, bad syntax, greylisted, unknown.
💳
Built-in billing
Stripe, Paddle, Razorpay, Paystack, Flutterwave. Subscriptions + credit packs.
🛡️
Self-hosted & private
Your VPS, your database, your customer data. No third-party processing.
02 · Server requirements

What you need.

Three non-negotiable requirements. Miss any one of them and the product will not work.

⚠️ Critical: outbound port 25

Email verification is making SMTP connections on port 25. If your VPS provider blocks outbound port 25, every verification will time out. Do not use DigitalOcean, AWS EC2, Google Cloud, or Azure — they permanently block port 25 with no path to unblock.

Minimum specifications

ComponentMinimumRecommendedNotes
CPU1 vCPU2–4 vCPUPython engine is async I/O bound, not CPU bound
RAM1 GB4–8 GB1 GB is enough to start; 2+ GB for production
Disk20 GB SSD50+ GB NVMeUploads + database growth
OSUbuntu 22.04 LTSUbuntu 22.04 LTSOther Debian-based distros may work; not tested
Port 25Open outboundOpen outboundMandatory — see provider table below
Bandwidth100 Mbps1 GbpsSMTP probes are tiny (~1 KB each)

Software stack (auto-installed)

LayerVersion
PHP8.4
Laravel13.x
PostgreSQL17
Redis6+
Python3.10+
Node.js24 LTS
Nginx1.18+

Pre-flight check

Run this on your fresh VPS before installing. If port 25 is blocked, stop and switch providers.

$ timeout 10 bash -c 'cat < /dev/tcp/gmail-smtp-in.l.google.com/25' \
  && echo "✅ Port 25 OPEN — proceed with install" \
  || echo "❌ Port 25 BLOCKED — switch VPS provider"

# You should see: 220 mx.google.com ESMTP ... then ✅
03 · Installation

Up in under 2 minutes.

One command installs the entire stack — PHP, Python, PostgreSQL, Redis, Nginx, SSL, and the app itself.

1
Provision a Contabo VPS
Buy a VPS S (4 vCPU, 8 GB RAM) from contabo.com — ~€5.99/month. Choose Ubuntu 22.04 LTS. Port 25 is open by default, no support ticket needed.
2
Point your domain
Add two DNS A records pointing to your VPS IP:

yourdomain.com → your VPS IP
app.yourdomain.com → your VPS IP

Important: Use DNS-only (grey cloud) in Cloudflare — do not proxy the app subdomain.
3
SSH in and run the installer
Connect to your VPS as root and paste one command. Watch it install live:
root@your-vps:~
ready
$
✓ MailTidy 3 is running — open https://app.yourdomain.com
4
Complete the setup wizard
Open https://app.yourdomain.com/setup. The wizard asks for your admin email/password, Envato purchase code, and basic settings. That's it.
✓ What the installer does not touch

Payment gateway keys, Google OAuth credentials, and SMTP settings are all configured after install through the admin panel. The installer never asks for sensitive API keys.

04 · First run

Verifying your first list.

1
Log in
Go to https://app.yourdomain.com. Sign in with the admin credentials you set in the wizard.
2
Upload a list
Click Upload list in the sidebar. Drag-drop a CSV, XLSX, or TSV file. Multi-column files work fine — MailTidy3 auto-detects the email column. Lists up to 100 MB and 500,000 emails are supported per job.
3
Watch it run
The job detail page shows live progress — throughput, classification breakdown, estimated completion time. For lists under 200 emails, verification starts immediately (no queue delay).
4
Export results
When complete, download a CSV of all results — or filter by status and export just that subset. Each result includes email, status, SMTP code, SMTP message, and MX host.
05 · Architecture

Three services, one purpose.

MailTidy3 splits concerns cleanly: Laravel handles the user-facing application, Python does the verification, workers scale the throughput.

Browser (React SPA)
       │  HTTPS / JSON API
       ▼
Laravel 13  (PHP 8.4)
  · Auth, billing, dashboard
  · Job state, file uploads
  · PostgreSQL 17 + Redis
       │  HTTP internal (localhost:8000)
       ▼
Python Engine  (FastAPI + asyncio)
  · Verification logic
  · Worker registry & dispatch
  · Per-domain rate limiting
  · Webhook results → Laravel
       │  HTTP (public, token-auth)
       ▼
Worker Agents  (one per VPS)
  · Polls engine for batches
  · Runs SMTP probes
  · Returns results

Why this separation?

PHP handles request/response well but can't do high-concurrency async I/O. Python (asyncio + aiosmtplib) can hold hundreds of SMTP connections in flight simultaneously. Laravel would block a PHP-FPM worker for the entire duration of a 100K-email job — Python never blocks at all.

Workers must run on separate IPs because Gmail, Yahoo, and Outlook rate-limit per source IP — not per account. Each additional worker VPS = one more independent rate-limit budget = roughly linear capacity increase.

Data flow for a verification job

#StepWho does it
1Buyer uploads CSV → Laravel parses, creates job recordLaravel
2Job dispatched to Python engine via internal HTTPLaravel → Python
3Engine splits into batches of 200, queues in RedisPython engine
4Workers poll for batches, run SMTP probes concurrentlyWorker agents
5Results returned to engine, progress webhooks sent to LaravelPython → Laravel
6Laravel writes results to DB, notifies buyerLaravel
06 · Email classifications

Nine ways an email can be classified.

Every email gets one primary status. Role-based is a flag that can appear alongside any status.

✓ Valid
SMTP server returned 250 on RCPT TO. The mailbox exists and accepts mail.
✗ Invalid
SMTP server returned 550 or other 5xx. Mailbox does not exist.
≈ Catch-all
Domain accepts any address — even random ones. Deliverability uncertain.
⊙ Disposable
Domain is a known temporary/throwaway email provider.
⊕ Role-based
Local part is a generic role: info@, support@, admin@, sales@.
∅ No MX
Domain has no MX records in DNS. Cannot receive email.
⊘ Bad syntax
Address fails RFC 5322 format check before any DNS or SMTP attempt.
⏳ Greylisted
Server returned 4xx (temporary rejection). May succeed on retry.
? Unknown
Connection error, timeout, or non-conforming SMTP response.
💡 Catch-all detection

When RCPT TO returns 250, MailTidy3 immediately probes a random address at the same domain (e.g. ck-a7f3b2c1d9@domain.com). If that also returns 250, the domain is catch-all. This eliminates false "valid" classifications.

07 · Real benchmarks

Numbers from actual tests.

These benchmarks were run on a single Contabo VPS (2 vCPU, 3.8 GB RAM) before the MailTidy3 rebuild was committed. They are not marketing estimates.

Per-email speed

Old MailTidy (PHP)
3–5 sec
MailTidy3 (Python)
0.28 sec

Sustained throughput (single VPS)

ConcurrencyEmails/secNotes
108.9Underutilising the network
3014.2Sweet spot for a 2 vCPU box
5017.6Diminishing returns begin
10019.1Memory pressure; not worth it

Soft-block wall

Gmail and other major providers rate-limit by source IP. During testing, sustained probing from a single IP hit a soft-block at approximately 4,400 emails. Recovery took 30 minutes of zero traffic. MailTidy3 handles this automatically with per-domain semaphores and auto-cooldown.

Realistic daily capacity

SetupEmails/day
1 VPS (main only)50,000 – 150,000
2 VPS (main + 1 worker)100,000 – 300,000
5 VPS250,000 – 750,000
10 VPS500,000 – 1.5 million
08 · Uploading lists

Any file, any structure.

MailTidy3 accepts CSV, XLSX, XLS, TSV, and TXT files up to 100 MB. Multi-column files are fully supported — the engine scans the first 100 rows to identify which column contains email addresses. If multiple columns look like emails, a column picker appears.

Accepted formats

FormatExtensionNotes
CSV.csvComma-separated. Headers optional.
Excel.xlsx, .xlsFirst sheet used. Multi-column supported.
TSV.tsvTab-separated.
Plain text.txtOne email per line.

Upload options

OptionDefaultDescription
Skip first rowOnTreat the first row as a header and skip it
DeduplicateOnRemove exact duplicate addresses before verifying
⚡ Small-list fast path

Lists of 200 emails or fewer bypass the background queue and run synchronously — results appear in under 60 seconds. This threshold is configurable in the admin panel.

09 · REST API

Verify programmatically, at scale.

MailTidy3 includes a public REST API. Generate an API key in your dashboard and start verifying from any codebase.

LIVE SMTP PROBES · running on app.mailtidypro.com

Authentication

All API requests require a bearer token in the Authorization header:

Authorization: Bearer mtp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Verify a single email

POST https://app.yourdomain.com/api/v1/verify

{
  "email": "user@example.com"
}

// Response
{
  "email":        "user@example.com",
  "status":       "valid",
  "smtp_code":    250,
  "smtp_message": "2.1.5 OK",
  "mx_host":      "aspmx.l.google.com",
  "flags":        [],
  "duration_ms":  284
}

Bulk verify

POST https://app.yourdomain.com/api/v1/verify/bulk

{
  "emails": [
    "user1@example.com",
    "user2@example.com",
    "invalid@nonexistent.xyz"
  ]
}

// Response
{
  "job": {
    "id":     "job_abc123",
    "status": "processing"
  }
}

Rate limits & quotas

LimitDefaultWhere to change
Daily API calls per key10,000Admin → Settings → API
Bulk request size10,000 emailsAdmin → Settings → Engine
Rate limit (requests/min)60Admin → Settings → API
09b · Autoresponder integrations

Verified. Now what? Push to your ESP.

When a verification job finishes, push the verified addresses straight into your email marketing platform — no CSV export, no manual import. Nine integrations are bundled, including the two self-hosted ESPs that matter most to this audience.

Supported platforms

PlatformWhat you can doSelf-hosted
MailwizzLists · Tags · Custom fields
Acelle MailLists · Custom fields
MailchimpAudiences · Tags · Merge fields
Brevo (formerly Sendinblue)Contacts · Lists · Tags
Kit (formerly ConvertKit)Forms · Sequences · Tags
GetResponseCampaigns · Custom fields · Tags
ActiveCampaignLists · Tags · Custom fields
Campaign MonitorLists · Custom fields · Segments
MailerLiteGroups · Fields · Tags

How a push works

From the results page of any completed job, click Push to autoresponder. Pick a connected ESP, choose the target list/audience/group, decide which classifications to include (valid, catch-all, greylisted), map fields, add tags, and hit push. The job runs in the background — close the dialog and check Push History later for the per-status counts (added, updated, skipped, failed).

⚡ Connect once, push from every job

You set up each ESP once under Settings → Integrations. After that, every results page shows a Push to autoresponder button that uses the saved credentials. Credentials are encrypted at rest and never logged.

Mailwizz (self-hosted)

If you already run Mailwizz on your own server, this is the most direct integration — your verified contacts go straight into the same database your campaigns send from.

Step 1 — Find your Mailwizz API URL
It's your Mailwizz install plus /api, e.g. https://mail.yourdomain.com/api.

Step 2 — Generate a public API key
In Mailwizz Customer Area, go to API Keys → Create new. Copy the public key — Mailwizz uses public/private key signing, so the public key is what MailTidy3 needs.

Step 3 — Get the list UID
Go to Lists, open the target list, and look at the URL. The UID is the alphanumeric segment after /lists/. You'll need it when pushing.

Step 4 — Connect in MailTidy3
Go to Settings → Integrations → Mailwizz → Connect. Paste the API URL and public key. Click Test connection. On success, the list selector populates automatically — no need to copy the UID manually.

Acelle Mail (self-hosted)

The other major self-hosted ESP. Same direct database push, same workflow.

Step 1 — Find your Acelle API URL
Your install plus /api/v1, e.g. https://acelle.yourdomain.com/api/v1.

Step 2 — Generate an API token
In Acelle, go to Profile → API Token → Generate. Copy the token.

Step 3 — Connect in MailTidy3
Settings → Integrations → Acelle → Connect. Paste API URL and token. Test connection — your lists appear in the dropdown.

Mailchimp

Step 1 — Generate an API key
In Mailchimp, click your profile (top right) → Profile → Extras → API keys → Create A Key. The key looks like a1b2c3d4e5f6g7h8-us21. The suffix after the dash (us21) is your data centre — Mailchimp embeds it in the key itself.

Step 2 — Find your Audience ID
Go to Audience → All contacts → Settings → Audience name and defaults. The Audience ID is shown near the bottom — it's a 10-character alphanumeric string.

Step 3 — Connect
Settings → Integrations → Mailchimp → Connect. Paste the API key. Audiences populate automatically. Map fields like FNAME, LNAME, or any merge field you've added. Tags can be auto-applied (e.g. mailtidy-verified).

Brevo (formerly Sendinblue)

Step 1 — Generate an API key
In Brevo, click your account (top right) → SMTP & API → API Keys → Generate a new API key. Give it a name like "MailTidy 3" and copy the key (starts with xkeysib-).

Step 2 — Connect
Settings → Integrations → Brevo → Connect. Paste the API key. Lists load from your account. Optionally set default tags, then save.

Kit (formerly ConvertKit)

Step 1 — Get your API credentials
In Kit, go to Settings → Advanced → API. You need both the API Key (for general calls) and API Secret (for adding subscribers).

Step 2 — Connect
Settings → Integrations → Kit → Connect. Paste both keys. Kit organises subscribers around Forms and Sequences — pick which to push to. Tags can be applied to all pushed subscribers.

GetResponse

Step 1 — Generate an API key
In GetResponse, go to Menu (top left) → Integrations and API → API → Generate API key. Give it a label and copy the key.

Step 2 — Connect
Settings → Integrations → GetResponse → Connect. Paste the API key. Your campaigns (lists) populate automatically. Map custom fields, set tags, save.

ActiveCampaign

Step 1 — Get API URL and Key
In ActiveCampaign, go to Settings → Developer. You'll see your API URL (looks like https://youraccount.api-us1.com) and Key. Copy both.

Step 2 — Connect
Settings → Integrations → ActiveCampaign → Connect. Paste both values. Lists load. Map ActiveCampaign custom fields to MailTidy3 data, set tags, save.

Campaign Monitor

Step 1 — Get your API key
In Campaign Monitor, click your account name (top right) → Account Settings → API keys → Show API key. Copy it.

Step 2 — Find your Client ID
From the same Account Settings page, your Client ID is shown — it's a long alphanumeric string. You'll need it to identify the right account when multiple clients exist under one login.

Step 3 — Connect
Settings → Integrations → Campaign Monitor → Connect. Paste API key and Client ID. Lists load.

MailerLite

Step 1 — Generate an API token
In MailerLite, go to Integrations → API → Generate new token. Give it a name and copy the token. Note: MailerLite has both Classic and the new platform — make sure you're generating the token from the version you actually use.

Step 2 — Connect
Settings → Integrations → MailerLite → Connect. Paste the token. Groups populate (MailerLite uses Groups instead of Lists). Map custom fields, set tags, save.

Push options reference

OptionWhat it does
Status filterChoose which classifications to push. Default: only valid. Common alt: valid + catch_all.
Field mappingMap MailTidy3 data (email, first name, last name, custom CSV columns) to ESP merge fields.
TagsAuto-apply tags to every pushed subscriber, e.g. mailtidy-verified, april-2026.
Skip existingIf a subscriber is already on the target list, don't re-add or update them. Default: on.
Background processingPushes run in the queue. You can close the browser; the push completes and is logged.
Push historyEvery push is logged with timestamp, target ESP/list, counts (added / updated / skipped / failed), and any error messages.
⚠️ Push only what you've verified

It's tempting to push unknown results "just in case." Don't. The whole point of verification is to keep your sender reputation clean — pushing inconclusive results to your ESP defeats it. Stick to valid, optionally catch_all if you understand the trade-off.

For SaaS operators (Extended License)

If you run MailTidy3 as a SaaS for your own paying customers, the SaaS Admin includes a separate flow: SaaS Admin → Customer Lists → Push to autoresponder. This pushes your customer accounts (with consent) to your own marketing autoresponder — useful for product announcements, upgrade nudges, and onboarding sequences targeted at the people paying you.

🔒 Consent gate

Customer-list export is gated by an explicit consent setting in SaaS Admin → Settings → Customer Communications. It's off by default. Customers can also opt out individually from their account page.

10 · Worker scaling

Add a worker, double the throughput.

Each worker VPS runs a single Python agent that polls the engine for email batches. Workers on different IPs have independent rate-limit budgets with Gmail, Yahoo, and Outlook.

When to add workers

The main VPS handles ~150,000 emails/day comfortably. Add workers if you regularly process lists over 100,000 emails, run multiple client lists simultaneously, or need guaranteed same-day turnaround on large batches.

Adding a worker — 3 steps

1
Generate a worker token
In your dashboard, go to Workers → Add worker. Copy the generated token — it looks like lic_a1b2c3d4...
2
Provision a new VPS
Same requirements as the main VPS — port 25 must be open, Contabo recommended. A 2 vCPU / 4 GB box is enough for a worker.
3
Run the one-liner
$ curl -fsSL https://install.mailtidypro.com/worker | bash -s \
  YOUR_TOKEN_HERE \
  https://app.yourdomain.com
The worker appears in your dashboard within 30 seconds. Batches automatically distribute across all registered workers from the next job onwards.
⚠️ Same VPS ≠ more throughput

Running a worker on the same VPS as the main install gains nothing — same IP = same rate-limit budget. Workers only add capacity when they run on different IPs.

11 · Admin panel

Full control, one place.

The admin panel is available to accounts with the admin role. The Extended License additionally unlocks the SaaS Admin section for running MailTidy3 as a multi-tenant service.

Admin capabilities

SectionWhat you can do
Settings → GeneralApp name, support email, enable/disable registrations
Settings → EngineEngine URL, batch size, max emails per job, file size limits
Settings → SMTPConfigure outgoing email for notifications, password reset, verification
Settings → AuthToggle email verification, free credits on signup, auto-approve
Settings → Google OAuthEnable Google login; shows button on login page when credentials are set
Settings → AppearanceAccent color, logo, font
UsersView, suspend, activate, delete users; edit credit balances
WorkersView active workers, kill ghost workers, toggle small-list bypass

Extended license (SaaS Admin)

SectionWhat you can do
Revenue dashboardMRR, total users, verification volume, recent transactions
User managementFull CRUD on all users, plan changes, credit editing, export CSV
PricingEdit plan names, prices, verification limits; toggle active/inactive
12 · SMTP configuration

Sending emails from your install.

MailTidy3 sends emails for: account verification, password reset, and job completion notifications. These go through the SMTP settings you configure in the admin panel.

Recommended providers

ProviderFree tierNotes
Resend3,000/monthBest developer experience, easy DNS setup
Mailgun100/dayReliable, good for transactional
SendGrid100/dayWell-known, easy SPF/DKIM
Gmail SMTP500/dayWorks for small installs; requires App Password

Settings

SettingExample
SMTP Hostsmtp.resend.com
SMTP Port587 (TLS) or 465 (SSL)
Encryptiontls
Usernameresend (or your email)
Passwordyour API key / app password
From Emailnoreply@yourdomain.com
From NameMailTidy3
💡 Email verification toggle

If you haven't configured SMTP yet, go to Settings → Auth → Require email verification and turn it off. Users can log in immediately after signup. Turn it back on once SMTP is working.

13 · License activation

Regular vs Extended.

FeatureRegular ($229)Extended ($1,499)
Email verification engine
REST API
Multi-worker scaling
Single-user install
SaaS multi-tenant (sell to others)
Revenue dashboard
User management panel
Pricing plan editor

How to activate

Go to Settings → Envato License. Select your license type, paste your Envato purchase code, and click Activate. The purchase code is in your Envato account under Downloads → License certificate & purchase code.

14 · VPS provider guide

Where to host.

🚫 Do not use DigitalOcean

DigitalOcean permanently blocks outbound port 25 at the hypervisor level. There is no ticket, no business plan, and no workaround. If you install MailTidy3 on DigitalOcean, every single verification will return a timeout error. Same applies to AWS EC2, Google Cloud, and Azure.

ProviderPort 25Recommended?Notes
ContaboOpen by default✅ Primary (EU)~€6/mo · 4 vCPU / 8 GB · best value · tested April 2026
RackNerdOpen by default✅ Primary (US)~$22/yr · US-based · affordable · tested April 2026
VultrUnlock on request✅ Good backupEmail support; say "email list verification"
HetznerBlocked 30 days⚠️ Slow startEU-only; unlocks after 30-day clean account
DigitalOceanPermanently blocked❌ NeverNo path to unblock. Do not use.
AWS EC2Blocked by default❌ AvoidUnblock form exists but usually denied
Google CloudPermanently blocked❌ NeverNo unblock path
AzurePermanently blocked❌ NeverNo unblock path
💡 Our recommendation

Contabo (~€6/mo) — port 25 open by default, proven reliable, best price/performance. Used in the MailTidy 3 production infrastructure powering this demo.

Reference · Deliverability

Maximum deliverability.
Best results, stay unblocked.

MailTidy3 is already built with anti-block mechanisms baked in — per-domain semaphores, automatic soft-block detection, 30-minute IP cooldowns, and multi-worker routing. But there are five additional steps you should complete on every VPS you install, including workers. They take under an hour total and the difference in accuracy is significant.

⚡ Do these before your first real job

Skipping these steps won't stop the install from working — but you'll see more unknown results, faster soft-blocks, and lower accuracy on Gmail and Yahoo specifically. None of these require a developer. Each step has a verification command so you know it worked.

Step 1 — Set reverse DNS (PTR record) Most important

When your VPS connects to Gmail's mail server, Gmail does a reverse DNS lookup on your IP. If the IP doesn't resolve back to a proper hostname, Gmail silently downgrades or rejects the conversation. This is the single most common cause of unknown results on a fresh install.

You need one PTR record per VPS — set from the Contabo control panel, not from DNS. DNS A records alone are not enough.

What to set

VPSIP addressPTR value to setMatching A record needed
Main installYour main VPS IPmail.yourdomain.commail.yourdomain.com → your IP
Worker 1Your worker VPS IPmail2.yourdomain.commail2.yourdomain.com → worker IP
Worker 2Your second worker IPmail3.yourdomain.commail3.yourdomain.com → worker 2 IP

How to set it on Contabo

1
Log into Contabo control panel

Go to my.contabo.com → Your Services → VPS. Click the VPS you want to configure.

2
Find Reverse DNS

In the VPS detail page, look for the Reverse DNS or rDNS section. It shows your current PTR record — by default it's something like vmi123456.contaboserver.net.

3
Set the new PTR value

Enter mail.yourdomain.com (or mail2. for workers). Click Save. Important: the A record for mail.yourdomain.com must already exist in your DNS pointing to this VPS IP — Contabo validates this before accepting the PTR.

4
Wait 15–30 minutes, then verify

PTR records propagate slowly. After 20 minutes, run the verification command below.

# Verify PTR (reverse DNS) — replace with your actual IP
$ dig -x YOUR_VPS_IP +short
mail.yourdomain.com.   # ✅ correct
vmi123456.contaboserver.net.  # ❌ not set yet — wait longer or re-check Contabo panel

# Verify the forward lookup matches (FCrDNS check)
$ dig mail.yourdomain.com +short
YOUR_VPS_IP  # ✅ must match the IP above
Why FCrDNS matters

Gmail performs a Forward-Confirmed Reverse DNS check: IP → PTR → hostname → A record → must resolve back to the same IP. All three must be consistent. If mail.yourdomain.com resolves to a different IP than the one connecting, the check fails even if the PTR is set.

Step 2 — Add your VPS IPs to SPF

SPF (Sender Policy Framework) tells receiving mail servers which IPs are authorised to send mail from your domain. The engine sends MAIL FROM: verify@yourdomain.com during every probe. Without your VPS IPs in the SPF record, the probe gets a softfail (~all) which some providers treat as suspicious.

Go to your DNS provider (Cloudflare, Namecheap, etc.) and find the TXT record for your domain. Edit the existing SPF record — do not add a second one, two SPF records on the same domain breaks SPF entirely.

# If you have Google Workspace email (support@yourdomain.com):
v=spf1 include:_spf.google.com ip4:MAIN_VPS_IP ip4:WORKER_1_IP ip4:WORKER_2_IP ~all

# If you don't use Google Workspace:
v=spf1 ip4:MAIN_VPS_IP ip4:WORKER_1_IP ~all

# Add each worker IP as a new ip4: entry when you add workers
# Verify SPF propagated (takes 1–5 minutes on Cloudflare)
$ dig TXT yourdomain.com +short | grep spf
"v=spf1 include:_spf.google.com ip4:84.46.245.142 ~all"  # ✅

Step 3 — Set the correct HELO hostname per worker

During every SMTP probe, the engine introduces itself with an EHLO command: "Hello, I am mail.yourdomain.com." The receiving server cross-checks this hostname against the connecting IP. A mismatch — or a generic Contabo hostname like vmi123456.contaboserver.net — causes Gmail to treat the connection as suspicious.

Each worker should EHLO with its own dedicated hostname that has a matching A record and PTR.

VPSHELO hostname to useWhere to set it
Main installmail.yourdomain.com/opt/mailtidy-engine/.envSMTP_HELO_DOMAIN
Worker VPSmail2.yourdomain.com/opt/mailtidy-worker/.envMAILTIDY_HOSTNAME
# Main VPS — edit /opt/mailtidy-engine/.env
SMTP_HELO_DOMAIN=mail.yourdomain.com
SMTP_MAIL_FROM=verify@yourdomain.com

# Worker VPS — edit /opt/mailtidy-worker/.env
MAILTIDY_HOSTNAME=mail2.yourdomain.com
# After editing, restart the relevant service

# On main VPS:
$ sudo systemctl restart mailtidy-engine

# On worker VPS:
$ sudo systemctl restart mailtidy-worker

Step 4 — Check your IP is not already blacklisted

If your VPS IP is listed on Spamhaus SBL, CBL, or similar RBLs, every single probe will be rejected before it even gets a real response. This is the first thing to check when you see 100% unknown results on a fresh install.

Run this on each VPS immediately after provisioning, before installing anything:

# Get your public IP
$ curl -s ifconfig.me
84.46.245.142

# Check Spamhaus — reverse the IP octets before the lookup
# For IP 84.46.245.142 → check 142.245.46.84.zen.spamhaus.org
$ dig +short 142.245.46.84.zen.spamhaus.org
# No output = not listed ✅
# 127.0.0.2 or similar = listed ❌

# Easy web alternative: https://mxtoolbox.com/blacklists.aspx
If your IP is listed

Contact Contabo support and request a replacement IP for the VPS. Mention you're running email verification software and the current IP has a poor reputation from a previous tenant. Contabo can usually replace it within a few hours. If the replacement is also listed, provision a fresh VPS — listed IPs come from recycled tenants who sent spam.

Step 5 — Understand the rate limits and work with them

MailTidy3's engine already enforces per-domain concurrency limits and automatic cooldowns. Understanding how the limits work helps you get the most out of each IP without triggering blocks.

ProviderPractical daily limit per IPWhat happens if exceededRecovery time
Gmail / Google~4,000–5,000 probesConnections time out silently~30 minutes
Yahoo / AOL~3,000–4,000 probes421 temporary rejection~20–30 minutes
Outlook / Hotmail~2,000–3,000 probesConnection refused or 421~60 minutes
Custom domainsVaries widelyUsually 421 greylisting~5–15 minutes

The engine detects soft-blocks automatically — when error rate exceeds 80% for a provider on a given IP, that IP is put into a 30-minute cooldown for that provider only, and remaining emails are routed to other healthy worker IPs. You can monitor this in real time on the Workers → IP Health panel in your admin dashboard.

The math on daily capacity

Each worker VPS is one IP and one independent rate-limit budget. If you regularly process lists with more than 50% Gmail addresses and need 50,000+ per day, you need at least 2 workers. The Adding workers guide shows how to add one in under 5 minutes.

SetupRealistic daily capacity
1 VPS (main only)50,000–150,000 emails/day
2 VPS (main + 1 worker)100,000–300,000 emails/day
5 VPS250,000–750,000 emails/day
10 VPS500,000–1,500,000 emails/day

Quick checklist — do this for every VPS

Run through this for your main VPS and every worker you add. The whole process takes about 20 minutes per VPS (mostly waiting for PTR propagation).

Port 25 outbound is open
Run the pre-flight check from Server requirements. If blocked — wrong provider, stop here.
IP not blacklisted on Spamhaus
Check with dig +short REVERSED_IP.zen.spamhaus.org. No output = clean.
A record added in DNS
e.g. mail.yourdomain.com → YOUR_IP. DNS only — no Cloudflare proxy (grey cloud, not orange).
PTR record set in Contabo panel
YOUR_IP → mail.yourdomain.com. Set from Contabo control panel → rDNS. Wait 20 min, verify with dig -x YOUR_IP +short.
SPF record includes this IP
Edit your domain's SPF TXT record to add ip4:YOUR_IP. Never add a second SPF record.
HELO domain set correctly
Main VPS: SMTP_HELO_DOMAIN=mail.yourdomain.com in /opt/mailtidy-engine/.env. Workers: MAILTIDY_HOSTNAME=mail2.yourdomain.com in /opt/mailtidy-worker/.env. Restart services after editing.
Test a real probe end-to-end
Use a known-valid email address via the API. Expect status: valid, smtp_code: 250, and duration_ms under 1000. If you see unknown with no smtp_code and ~10000ms duration, something above is misconfigured.

End-to-end test after setup

After completing all five steps, test with a known-valid email address using your API key. A correct result looks like this:

$ curl -s \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"known-valid@gmail.com"}' \
  https://app.yourdomain.com/api/v1/verify | python3 -m json.tool
✅ Correct result — everything is configured properly:
{
  "email":        "known-valid@gmail.com",
  "status":       "valid",
  "smtp_code":    250,
  "smtp_message": "2.1.5 OK ...",
  "mx_host":      "aspmx.l.google.com",
  "duration_ms":  312.4    ← under 1 second = healthy connection
}

❌ Problem result — PTR/HELO misconfigured or IP blocked:
{
  "status":      "unknown",
  "smtp_code":   null,
  "error":       "timeout",
  "duration_ms": 10014.6   ← 10 seconds = connection never completed
}
📊 Monitor IP health in real time

The Workers page in your admin dashboard includes a live IP Health panel. It shows per-provider status for every registered worker IP — whether it's healthy or in a cooldown, the recent error rate, and how many minutes remain in any active cooldown. Cooldowns are automatic and self-healing. You can also manually force or clear a cooldown from the panel without touching the server.

15 · Troubleshooting

When things go wrong.

All verifications return UNKNOWN

Cause: Port 25 is blocked on your VPS, or aiosmtplib is attempting STARTTLS and failing SSL validation.

Test: timeout 10 bash -c 'cat < /dev/tcp/gmail-smtp-in.l.google.com/25' — should print a 220 banner.

Fix: Switch to Contabo or Vultr (with port 25 unlocked). Ensure the worker service runs as root.

Results table shows "No results match this filter"

Cause: Hard-cached browser assets. Fix: Ctrl+Shift+R (hard refresh).

Job stuck at 0% / never starts

Check queue workers: sudo supervisorctl status — both mailtidy-queue processes should be RUNNING.

Check engine: curl http://127.0.0.1:8000/health/live — should return {"status":"ok"}.

Restart everything: sudo systemctl restart mailtidy-engine mailtidy-worker && sudo supervisorctl restart mailtidy-queue:*

Ghost workers in the workers panel

Cause: A worker registered and then the engine restarted, losing its memory.

Fix: Click Kill ghosts in the Workers panel, or restart the engine: sudo systemctl restart mailtidy-engine

Log locations

# Engine logs
$ sudo tail -f /var/log/mailtidy-engine/engine.log

# Worker logs
$ sudo tail -f /var/log/mailtidy-engine/worker.log

# Laravel logs
$ sudo tail -f /var/www/mailtidy/storage/logs/laravel.log

# Nginx logs
$ sudo tail -f /var/log/nginx/error.log
16 · Gmail & IP reputation

Why Gmail says unknown.

You install MailTidy3, run your first verification, and Yahoo addresses come back in 1.5 seconds — clean, accurate, perfect. But every Gmail address times out at 10 seconds and returns unknown. Nothing is broken. This is Gmail deliberately ignoring you, and there is a precise fix.

The mental model

Gmail's mail servers answer every knock — but only from visitors who look legitimate. Your VPS has a generic datacenter name, so Gmail holds the door open in silence until you give up and leave.

What actually happens under the hood

When MailTidy3 verifies an email address, it connects to the recipient's mail server on port 25 and has a short SMTP conversation — no actual email is ever sent. Gmail's MX servers (gmail-smtp-in.l.google.com) accept the TCP connection from your IP, but before responding they do a reverse DNS lookup (PTR record) on your IP address.

What they find on a fresh Contabo VPS is something like vmi1478013.contaboserver.net — a generic hostname that millions of spam servers also have. Gmail's response: silently hold the connection open for 10 seconds, then drop it. Your verification returns unknown. This is not a bug. It is Gmail protecting its users from probes it cannot verify.

What Gmail does with your probe
Your VPS
84.46.245.142
SMTP probe →
Gmail MX
PTR lookup on IP
Who are you?
Result
vmi1478013.
contaboserver.net
❌ Ignored. Timeout.
Your VPS
84.46.245.142
SMTP probe →
Gmail MX
PTR lookup on IP
Who are you?
Result
mail.yourdomain
.com ✓
✅ Responds in <2s
Before fix (top) vs after fix (bottom)

How to diagnose it

First, confirm the problem is rDNS and not a soft-block. Run these two tests back-to-back on your VPS:

# Test 1 — Does Yahoo work fast? (it should)
$ curl -s -w "\nTime: %{time_total}s\n" https://app.yourdomain.com/api/v1/verify \
  -X POST \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"test@yahoo.com"}'
# Expect: status "valid" or "catch_all" in ~1-2 seconds

# Test 2 — Does Gmail time out?
$ curl -s -w "\nTime: %{time_total}s\n" https://app.yourdomain.com/api/v1/verify \
  -X POST \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"someone@gmail.com"}'
# If this takes 10 seconds and returns "unknown" — it's rDNS.
# Check your current PTR record
$ dig -x YOUR_VPS_IP +short
# Bad:  vmi1478013.contaboserver.net.
# Good: mail.yourdomain.com.

The fix — 2 steps, 5 minutes

1
Set the PTR record in Contabo

Log in to contabo.com → left sidebar → Reverse DNS Management. Find your VPS IP and set the PTR value to mail.yourdomain.com (replace with your actual domain). Save.

Contabo — Reverse DNS Management
IP Address
PTR Record (Data)
Action
185.215.x.x
vmi1487602.contaboserver.net
✏️
84.46.245.142
mail.mailtidypro.com ← set this
✏️ Save
2
Add a matching A record in your DNS control panel

The PTR record says "this IP belongs to mail.yourdomain.com". Gmail then checks the other direction — it looks up mail.yourdomain.com and expects to get your IP back. Both must match or Gmail still rejects you.

In your DNS control panel (Cloudflare, GoDaddy, Namecheap, or wherever your domain is managed), add an A record:

Your DNS control panel — Add A Record
Type
Name
IPv4 Address
Proxy
A
mail
84.46.245.142
DNS only
⚠️  If using Cloudflare: grey cloud only (DNS only) — do NOT enable the proxy (orange cloud) for this record

Verify it worked

PTR propagation typically takes 30–60 minutes. Run this to check:

# Both commands should reference each other
$ dig -x 84.46.245.142 +short
mail.mailtidypro.com.   # ← should return your domain, not contaboserver.net

$ dig mail.mailtidypro.com A +short
84.46.245.142           # ← should return your IP

Once both match, test Gmail verification directly:

$ curl -s -w "\nTime: %{time_total}s\n" https://app.yourdomain.com/api/v1/verify \
  -X POST \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"someone@gmail.com"}'
# After fix: status "valid" or "invalid" in under 2 seconds.
# Before fix: status "unknown" after exactly 10 seconds.
❌ Before
PTR: vmi1478013.contaboserver.net
Gmail response: silent timeout
Duration: 10,000 ms
Status: unknown
✅ After
PTR: mail.mailtidypro.com
Gmail response: SMTP 250 / 550
Duration: < 1,500 ms
Status: valid / invalid
📝 Worker VPS need this too

Every VPS you add as a verification worker has its own IP — and its own rDNS problem. When you add a worker, set the PTR for that IP to something like worker1.yourdomain.com and add the matching A record in Cloudflare. Same two steps, different hostname.

💡 What about Microsoft / Outlook addresses?

Microsoft's servers behave similarly but for a different reason — they whitelist known senders. rDNS helps, but Outlook and Hotmail addresses may still return unknown from fresh IPs. This is a Microsoft policy limitation, not a MailTidy3 bug. The classification is honest: if Microsoft won't say, neither will we.

16c · Diagnostic tools

Six tools, built in.

Email deliverability lives or dies on DNS. MailTidy3 ships six diagnostic tools that let you check the records that matter — without leaving the dashboard or pasting your domain into someone else's site.

Open Diagnostics → Tools in the sidebar. Every user (including demo accounts) can run them; results are cached for six hours per (domain or IP, tool) pair so repeated checks are instant. All six are also exposed as API endpoints for Extended License holders.

The six tools

ToolWhat it answersInput
DMARC CheckerIs the domain's DMARC policy published, and what does it say (none / quarantine / reject)?Domain
SPF CheckerDoes the SPF record exist, parse cleanly, and have a valid all mechanism?Domain
DKIM CheckerAre DKIM keys published? Auto-scans 14 common selectors (default, google, k1, selector1…) in parallel.Domain (+ optional selector)
rDNS / PTR CheckerDoes the IP resolve back to a hostname? Is FCrDNS chain valid (PTR → A → original IP)?IP address
Blacklist CheckerIs the IP listed on any of 8 major RBLs (Spamhaus, Barracuda, SORBS, etc.)? Cached 6 hours.IP address
SMTP TesterConnect to an SMTP server, run AUTH, and report the full step-by-step conversation. Credentials never stored.Host, port, credentials

Input persistence between tools

Type a domain into the SPF Checker, then jump to the DMARC or DKIM Checker via the switcher strip — the domain is already filled in. Same for IP-based tools (rDNS and Blacklist share the IP field). It's stored in sessionStorage, so it clears when you close the tab.

Tool API (Extended License)

Each tool is also a REST endpoint. Useful if you want to surface the results inside another product or run scheduled checks on your own infrastructure.

Authentication — the tool API uses the same bearer-token scheme as /api/v1/verify. Generate a key in Settings → API Keys; the key must be issued under an Extended License (or by an admin) to access tool routes.

POST https://app.yourdomain.com/api/v1/tools/spf
Authorization: Bearer mtp_live_xxxxxxxxxxxxxxxx
Content-Type: application/json

{
  "domain": "example.com"
}

// Response
{
  "domain":        "example.com",
  "record":        "v=spf1 include:_spf.google.com ~all",
  "valid":         true,
  "all_mechanism": "~all",
  "includes":      ["_spf.google.com"],
  "warnings":      [],
  "checked_at":    "2026-05-05T12:34:56Z"
}

All tool endpoints

EndpointBody
POST /api/v1/tools/dmarc{ "domain": "..." }
POST /api/v1/tools/spf{ "domain": "..." }
POST /api/v1/tools/dkim{ "domain": "...", "selector": "default" } (selector optional)
POST /api/v1/tools/rdns{ "ip": "..." }
POST /api/v1/tools/blacklist{ "ip": "..." }
POST /api/v1/tools/smtp{ "host": "...", "port": 587, "username": "...", "password": "..." }

Rate limits

RouteLimitNotes
/api/tools/* (session)50 / day per userAvailable to all users including demo accounts.
/api/v1/tools/* (API key)Per-key daily quotaExtended License only. Counts against the same quota as /api/v1/verify.
🔒 SMTP Tester credentials are never stored

The SMTP Tester opens a one-shot connection, reports the result, and forgets. Credentials aren't logged, persisted, or cached. The same applies to the API endpoint — request bodies pass through the controller and are immediately discarded after the SMTP transaction completes.

⚡ Run the tools after every new VPS

When you provision a new worker, the four-check sequence is: rDNS → SPF → Blacklist → SMTP Tester. If those four pass cleanly, your IP is ready to verify against Gmail/Yahoo/Outlook without surprises. Maximum deliverability covers the full setup.

16b · Billing & Payment Gateways

Accept payments. Your gateway, your money.

MailTidy3 supports five payment gateways. Each is off by default — you enable only the one(s) you want. All configuration is done through the admin panel; no `.env` editing is needed after install.

Go to Admin → Settings → Payment Gateways to configure any gateway. Changes take effect immediately — no server restart required.

⚡ Which gateway should I choose?

Use Stripe if you're based in the US, UK, EU, or Australia — it has the best developer experience and widest currency support. Use Razorpay for India. Use Paystack or Flutterwave for Africa. Use Paddle if you want them to handle VAT/tax compliance automatically (they act as merchant of record).

Stripe

Stripe is the recommended gateway for most installs. It supports subscriptions, one-time payments, and automatic invoicing in 135+ currencies.

Step 1 — Create a Stripe account
Go to stripe.com and sign up. Complete identity verification before going live.

Step 2 — Get your API keys
In the Stripe Dashboard go to Developers → API keys. Copy your Publishable key (pk_live_...) and Secret key (sk_live_...). Use test keys (pk_test_... / sk_test_...) while testing.

Step 3 — Create your products
In Stripe Dashboard go to Product catalogue → Add product. Create one product per plan that matches what you've set up in Admin → Pricing. For each product, set a recurring price (monthly or yearly). Copy the Price ID (price_xxx) — you'll need it in the next step.

Step 4 — Enter credentials in MailTidy3
Go to Admin → Settings → Payment Gateways → Stripe. Enter your Publishable key, Secret key, and the Price IDs for each plan. Toggle Enable Stripe on. Click Save.

Step 5 — Set up the webhook
In Stripe Dashboard go to Developers → Webhooks → Add endpoint. Set the endpoint URL to:

https://app.yourdomain.com/api/billing/stripe/webhook

Select these events: customer.subscription.created, customer.subscription.updated, customer.subscription.deleted, invoice.payment_succeeded, invoice.payment_failed.
Copy the Webhook signing secret (whsec_...) and paste it into Admin → Settings → Payment Gateways → Stripe → Webhook Secret.

Step 6 — Test it
Use Stripe's test card 4242 4242 4242 4242 (any future expiry, any CVC) to complete a test purchase. Confirm the subscription appears in Admin → Billing.

🔴 Never share your Secret key

The Secret key (sk_live_...) must only be entered in the admin panel. Never paste it in a browser console, email, or chat.

Paddle

Paddle acts as the merchant of record — they handle VAT, GST, and sales tax on your behalf. Ideal if you sell globally and don't want to deal with tax compliance yourself.

Step 1 — Create a Paddle account
Go to paddle.com. Paddle requires business verification before you can go live — allow 1–3 business days.

Step 2 — Get your API credentials
In the Paddle Dashboard go to Developer Tools → Authentication. Copy your Vendor ID and generate an API key. Also note your Client-side token for the frontend.

Step 3 — Create your plans in Paddle
Go to Catalog → Products. Create a product for each plan. Under each product, create a Price (recurring). Copy the Price ID for each.

Step 4 — Enter credentials in MailTidy3
Go to Admin → Settings → Payment Gateways → Paddle. Enter your Vendor ID, API key, Client-side token, and Price IDs. Toggle Enable Paddle on. Click Save.

Step 5 — Set up the webhook
In Paddle Dashboard go to Developer Tools → Notifications → New destination. Set URL to:

https://app.yourdomain.com/api/billing/paddle/webhook

Select all subscription and payment events. Copy the secret key Paddle generates and enter it in Admin → Settings → Payment Gateways → Paddle → Webhook Secret.

Razorpay (India)

Razorpay is the most popular payment gateway for India, supporting UPI, NetBanking, cards, and wallets in INR.

Step 1 — Create a Razorpay account
Go to razorpay.com. Complete KYC verification. You can use test mode immediately without KYC.

Step 2 — Get API keys
In the Razorpay Dashboard go to Settings → API Keys → Generate Test Key (or Live Key). Copy the Key ID (rzp_live_...) and Key Secret.

Step 3 — Create plans in Razorpay
Go to Subscriptions → Plans → Create plan. Create one plan per pricing tier. Copy the Plan ID (plan_...) for each.

Step 4 — Enter credentials in MailTidy3
Go to Admin → Settings → Payment Gateways → Razorpay. Enter your Key ID, Key Secret, and Plan IDs. Toggle Enable Razorpay on. Click Save.

Step 5 — Set up the webhook
In Razorpay Dashboard go to Settings → Webhooks → Add new webhook. Set URL to:

https://app.yourdomain.com/api/billing/razorpay/webhook

Select events: subscription.activated, subscription.charged, subscription.cancelled, payment.captured, payment.failed.
Enter a Webhook Secret of your choice and paste the same value in Admin → Settings → Payment Gateways → Razorpay → Webhook Secret.

Paystack (Africa)

Paystack is the leading gateway for Nigeria, Ghana, Kenya, and South Africa. Supports cards, bank transfers, and mobile money.

Step 1 — Create a Paystack account
Go to paystack.com. Business registration required for live mode.

Step 2 — Get API keys
In the Paystack Dashboard go to Settings → API Keys & Webhooks. Copy your Public Key (pk_live_...) and Secret Key (sk_live_...).

Step 3 — Create plans
Go to Products → Plans → Create Plan. Create one plan per pricing tier. Copy the Plan Code for each.

Step 4 — Enter credentials in MailTidy3
Go to Admin → Settings → Payment Gateways → Paystack. Enter your Public Key, Secret Key, and Plan Codes. Toggle Enable Paystack on. Click Save.

Step 5 — Set up the webhook
In Paystack Dashboard go to Settings → API Keys & Webhooks → Webhook URL. Set it to:

https://app.yourdomain.com/api/billing/paystack/webhook

Paystack signs all webhooks with your Secret Key — no separate webhook secret needed.

Flutterwave (Africa)

Flutterwave operates in 30+ African countries and supports cards, bank transfers, mobile money, and USSD.

Step 1 — Create a Flutterwave account
Go to flutterwave.com. Complete business verification for live mode.

Step 2 — Get API keys
In the Flutterwave Dashboard go to Settings → API → API Keys. Copy your Public Key, Secret Key, and Encryption Key.

Step 3 — Create payment plans
Go to Payment Plans → Create a plan. Create one plan per pricing tier. Copy the Plan ID for each.

Step 4 — Enter credentials in MailTidy3
Go to Admin → Settings → Payment Gateways → Flutterwave. Enter your Public Key, Secret Key, Encryption Key, and Plan IDs. Toggle Enable Flutterwave on. Click Save.

Step 5 — Set up the webhook
In Flutterwave Dashboard go to Settings → Webhooks. Set URL to:

https://app.yourdomain.com/api/billing/flutterwave/webhook

Generate a Secret Hash in the Flutterwave webhook settings and enter the same value in Admin → Settings → Payment Gateways → Flutterwave → Webhook Secret.

💡 Test before going live

Every gateway has a test/sandbox mode. Always complete a test transaction — including a simulated webhook — before switching to live keys. Your customers' first payment must work.

17 · FAQ

Common questions.

Does MailTidy3 send actual emails?

No. The verification engine connects to recipient mail servers, introduces itself (EHLO), and asks whether a mailbox exists (RCPT TO) — then disconnects before sending anything. No email is ever delivered.

Will my IP get blacklisted?

MailTidy3 uses per-domain rate limiting (max 5 concurrent probes per recipient domain) and automatic cooldown when error rates spike. During testing, 4,400+ emails through a single IP triggered a temporary Gmail soft-block — which cleared in 30 minutes. The system detects this automatically.

Can I white-label this for my customers?

Yes, with the Extended License. Install MailTidy3 on your own VPS, customize branding through the admin panel, point your domain at it, and sell verification credits to your customers.

What's the difference between Regular and Extended license?

Regular is for using MailTidy3 for your own email verification needs. Extended allows you to run it as a SaaS — charging your own customers for verification. See the license comparison table above.

How accurate is it?

In pre-launch testing across ~500 hand-verified results, classification was correct in every case. Catch-all detection was a major improvement over the original MailTidy — the new probe sends a random address before classifying as "valid".

Does it work with Outlook/Hotmail?

Microsoft's mail servers are conservative and don't always return definitive accept/reject responses for unrecognised source IPs. Results for @outlook.com and @hotmail.com will often come back as "unknown". This is a limitation of Microsoft's SMTP behaviour, not a bug.

Can I run it on 1 GB RAM?

Yes — 1 GB is enough to get started and test. For production workloads, 2–4 GB is recommended. The Python engine and Redis together use roughly 400–600 MB at rest.

Is there a hosted version?

Not currently. MailTidy3 is self-hosted only — you own the server and the data. A hosted cloud edition is on the roadmap.

I'm interested in MailTidy 3 →