IT

What Is BillionMail? Security Review and Whether to Self-Host Email Marketing

BillionMail is open-source software from aaPanel that bundles a mail server (Postfix, Dovecot, Rspamd, RoundCube) with an email marketing tool. The project has more than 16,000 stars on GitHub and advertises “unlimited email sending” after an 8-minute installation. I read the entire source code at commit fc36c76c (June 11, 2026) without running any installation scripts. The short conclusion: BillionMail is not ready for production email systems, and you should never install it on the same server as a live website.

What Is BillionMail?

BillionMail combines two things in a single Docker Compose stack: a mail server for receiving and sending email for your domain, and campaign management features including contact lists, email templates, scheduled sending, IP warmup, and open and click tracking. The core is written in Go (GoFrame), with a Vue 3 interface, PostgreSQL, and Redis. It is licensed under AGPL-3.0.

The advertised figures all check out against the GitHub API: 16,107 stars, 1,788 forks, and exactly 1,333 commits. But development has slowed considerably. There were 21 releases in 2025, from V0.01 to v4.9 (December 2025). From July through November 2026, the repository had no commits, while the number of open issues stood at 234.

Who Is aaPanel?

aaPanel is the international version of BaoTa (宝塔面板), a very popular hosting control panel in China. The panel has a worrying security history: a flaw allowing access to phpMyAdmin without logging in in 2020 (CNNVD-202008-1141), arbitrary command execution vulnerabilities CVE-2020-14421 and CVE-2020-14950, and, in 2026, CVE-2026-101008 and CVE-2026-101009 (command injection, CVSS scores above 9). For the two 2026 CVEs, aggregated sources report that the vendor did not respond to the researchers who reported them.

BillionMail follows the same pattern. Its initial vulnerability reporting channel was just a QQ email address. A report submitted through GitHub Security Advisory in October 2025 still had not been reviewed (issue #277). An arbitrary file read vulnerability publicly reported in August 2025 (issue #172) was patched in v4.4, but the issue remains open, with no notice to users running older versions.

Security Issues Found

1. The Docker Installation Method in the README Uses Public Default Secrets

The README provides a quick installation command: cp env_init .env && docker compose up -d. The env_init file includes the default administrator credentials billion/billion, the hidden path billion, and fixed PostgreSQL and Redis passwords (lines 2–18). These values are publicly available on GitHub, and the admin interface’s authentication depends on them. Any machine installed this way without changes to .env effectively has an unlocked admin interface. Installation through install.sh generates random passwords, so it is safer in this respect.

2. Arbitrary File Read Vulnerability: Patched but Not Announced

In versions up to v4.3, the two endpoints /file/read and /file/download allowed authenticated accounts to read any file in the container, including the .env file containing system passwords (issue #172). On August 22, 2025, commit 0325e001 disabled both endpoints entirely, so versions v4.4 onward are no longer affected. However, the issue remains open, with no advisory or release note. Anyone running v4.3 or earlier should update.

3. Predictable Signing Key

Unsubscribe and subscription confirmation tokens are signed with a key derived from configuration constants (core/internal/service/batch_mail/jwt.go, lines 98–120). This vulnerability has been assigned CVE-2026-111367. As a result, an outsider can add someone else’s email address to a mailing list without that person’s consent. Under anti-spam laws, this creates a direct legal risk for the system owner.

Click-tracking links are also “encrypted” with AES, but the key is embedded directly in the resulting string (maillog_stat/encryption.go, lines 16–36). Anyone can decrypt and recreate them, so your sending domain could be used to redirect people to phishing sites (issue #390).

4. The Admin Container Can Access Docker on the Host

The core container mounts /var/run/docker.sock (docker-compose.yml, line 195). The :ro flag does not restrict the Docker API, so compromising the admin interface effectively means compromising the entire host. This is why you should not install BillionMail alongside a website.

5. Installation and Update Scripts

  • install.sh must run as root, permanently disables SELinux (lines 287–288), and downloads Docker, docker-compose, and systemd units from node.aapanel.com with the --no-check-certificate flag, without verifying checksums (lines 812–832).
  • The script enables ufw with a default-deny policy, then opens mail ports, including unencrypted POP3 and IMAP (110, 143).
  • The bm update command downloads new code from GitHub, merges it using -X theirs to favor incoming changes, and then pulls images by tag without verifying signatures (update.sh, lines 224–267).
  • The billionmail/core image simply copies in a prebuilt executable, and the repository has no public CI. There is no way to prove that the image on Docker Hub matches the source code.
  • The repository even includes a committed TLS private key (ssl-self-signed/key.pem).

6. Sending Metrics to aaPanel

Every 2 hours, the software sends the number of emails sent and the number of relays to aapanel.com (core/internal/service/collect/collect.go), with no switch to disable it. The installation script also sends a ping to track installations. Email content and contact lists are not sent, but aaPanel knows your server’s IP address and email volume.

What It Gets Right

Postfix is configured correctly and is not an open relay: mynetworks includes only localhost, and reject_unauth_destination is enabled. It includes 2048-bit DKIM, an SPF template with -all, DMARC with p=quarantine, and Let’s Encrypt certificates. PostgreSQL and Redis listen only on localhost.

Will Outgoing Emails Reach the Inbox?

One omission directly affects inbox deliverability: BillionMail’s bulk emails lack the List-Unsubscribe header specified by RFC 8058. The sending code sets only Message-ID and the sender’s name. Gmail and Yahoo have required this header for bulk senders since 2024, Outlook has enforced it since May 2025, and Gmail began rejecting noncompliant emails in November 2025.

Beyond the software itself, self-hosting email also faces practical barriers:

  • Many providers block port 25: DigitalOcean, Vultr, and Hetzner for new accounts; AWS EC2 until you submit a request to remove the restriction; and Google Cloud blocks it outright. Many Vietnamese VPS providers also block it or require registration.
  • You need a clean IP address, a PTR record matching the hostname, SPF, DKIM, DMARC, and registration with Google Postmaster Tools and Microsoft SNDS.
  • A new IP needs 2 to 6 weeks of warmup, with the spam complaint rate kept below 0.1% (Gmail’s hard threshold is 0.3%).

So “unlimited sending” only means the software does not count emails. The real limits are your IP and domain reputation. After warmup, a new IP can realistically deliver a few thousand emails a day to inboxes, not millions.

Compared with Listmonk, Mailcow, Postal, and Mautic

  • Listmonk: list and campaign management, written in Go, lightweight and stable, sends through external SMTP or Amazon SES, and includes List-Unsubscribe.
  • Mailcow: a mature Docker mail server stack with a focus on security. BillionMail’s mail server component is a simpler version.
  • Postal: a bulk-sending MTA, similar to a self-hosted SendGrid, with an API and webhooks.
  • Mautic: full marketing automation (automated workflows, lead scoring), but resource-intensive.
  • Mailtrain: development has largely stopped, so it is not recommended for a new deployment.

Actual Costs Compared with Amazon SES, Resend, and Brevo

BillionMail is free, but it requires a VPS costing around USD 5 to 20 per month, plus the work of operating it, patching vulnerabilities, and dealing with blacklists. Amazon SES charges about USD 0.10 per 1,000 emails. Resend has a free plan with 3,000 emails per month and a Pro plan at around USD 20 for 50,000 emails. Brevo offers around 300 emails per day for free. At volumes of a few thousand to a few tens of thousands of emails per month, using an existing service costs less than the labor of operating your own mail server. These prices are indicative, so check each provider’s website.

  • AGPL-3.0: if you use it internally without modifying the code, no additional action is required. If you modify the code and make it available to others over a network, you must publish the modified code.
  • Decree 91/2020/NĐ-CP: send advertising emails only with the recipient’s prior consent, label the subject line as advertising, provide a way to opt out, and do not use unlawfully collected addresses.
  • CAN-SPAM and GDPR: use truthful subject lines, provide a contact address, and process unsubscribe requests promptly; explicit consent is required for recipients in the EU.

Should You Use BillionMail?

For a production email system, my answer is not yet. A safer approach is to use Listmonk (or Resend’s Broadcasts feature) to manage lists, then send through Resend or Amazon SES on a dedicated marketing subdomain.

If you still want to try BillionMail for learning or internal mailboxes:

  1. Install it on a separate, empty VPS. Ask the provider about port 25 and PTR records beforehand.
  2. Do not use env_init as instructed in the README. Generate all passwords yourself with openssl rand, set your own jwt.secret, and delete and regenerate the ssl-self-signed directory.
  3. Change the default IPV4_NETWORK range (172.66.1.0/24, which overlaps with Cloudflare’s IP range) to a range such as 10.66.1.0/24.
  4. Do not expose the admin interface to the Internet. Put it behind Cloudflare Tunnel and Cloudflare Access, or enable an IP allowlist.
  5. Close ports 110 and 143, and require TLS for login.
  6. Block outbound connections to aapanel.com and bt.cn, build the core image yourself from source, and do not run bm update.
  7. Send outbound email through an SES or Resend relay, but remember that bulk emails still lack the List-Unsubscribe header.

This article is based on reading the source code and public metadata from GitHub and Docker Hub; I did not run the software or log in to the demo site. Repository: github.com/aaPanel/BillionMail.

#bao-mat#billionmail#email-marketing

Bài liên quan

8 bài

XuanHieuAI

Bạn có gì muốn hỏi XuanHieuAI?

Đang tải…