Mailing policy — no bulk mail from BOA hosts

BOA hosts (both hosted-BOA at omega8.cc and self-hosted BOA in production) are not intended for bulk-mail sending. This page explains why and what to do instead.

The policy

BOA hosts: transactional mail OK, bulk mail NOT OK.

Allowed (transactional):

  • New-user-registration confirmations.
  • Password-reset mails.
  • Order receipts.
  • Form-submission notifications.
  • BOA's own system notifications (install/upgrade/incident reports).
  • BOA-originated client notices — the Let's Encrypt renewal-failure notices (below).

Not allowed (bulk):

  • Marketing newsletters to N+ recipients.
  • Mass campaign sends.
  • Automated drip sequences.
  • Re-engagement emails to inactive users.
  • Any send pattern that looks like marketing.

Why

1. IP reputation

A single BOA host serves many tenants' sites. One tenant's bulk-mail blunder (e.g. hitting a stale list and triggering high bounce rates) can land the host's IP on shared spam blocklists. That affects every other tenant's transactional mail — registrations bounce, password resets do not arrive, order confirmations get spam-foldered. Routing bulk mail through a dedicated email service provider (ESP) isolates the IP-reputation risk to that provider's actively-managed IP pool.

2. Anti-abuse enforcement

On hosted BOA (omega8.cc) this is enforced as a service-level policy: bulk-mail attempts may result in a temporary outbound-25 firewall block, a support ticket, or — in repeat cases — account suspension. This enforcement is operational (monitoring + support action), not an automated BOA volume-throttle baked into the stack — BOA ships no outbound-mail rate-limiter or volume monitor (the sendmail_guard.sh monitor only kills rogue root-owned sendmail MTA processes; it does not meter send volume).

On self-hosted BOA there is therefore no built-in throttle to rely on or disable: keeping within transactional limits is the operator's responsibility, and the upstream provider's own anti-spam policies (and any outbound-25 limits) still apply.

What to use instead

For bulk mail, use a dedicated Email Service Provider (ESP):

  • Transactional + bulk: Postmark, SendGrid, Mailgun, Amazon SES.
  • Bulk only / marketing: Mailchimp, ConvertKit, ActiveCampaign, Klaviyo.

Configure your Drupal site to use the ESP via SMTP relay or the provider's Drupal module. BOA does not care which ESP you use; the site sends through the ESP's API and BOA's local mail stack is bypassed for those sends.

Configuring an SMTP relay (transactional mail)

Even transactional mail benefits from going through an SMTP relay, especially if you would rather not manage SPF / DKIM / DMARC on the BOA host directly. In /root/.barracuda.cnf:

_SMTP_RELAY_HOST="smtp.your-provider.example.com"

_SMTP_RELAY_HOST defaults to empty ("") — direct local delivery — until you set it. This sets the Postfix relayhost, so it suits an unauthenticated relay (an IP-allowlisted provider, or your own outbound smarthost). After barracuda upgrade, outbound mail flows through the relay instead of direct delivery — unless local sendmail is enabled for hosted sites (next section).

For a relay that needs authentication, _SMTP_RELAY_HOST is the wrong tool — it carries no credentials. BOA ships aegir/tools/bin/smtpgapps, but note two limits before relying on it:

  • Gmail-only. It is hard-wired to Gmail: it validates the argument as a Gmail address, requires the password to be a 16-lowercase-letter Gmail App Password, and writes an /etc/msmtprc fixed to smtp.gmail.com:587. Any other provider needs /etc/msmtprc hand-edited afterwards.
  • It does not route mail on its own. smtpgapps only writes /etc/msmtprc (plus its log and logrotate). It does not touch Postfix, _SMTP_RELAY_HOST, or PHP's sendmail_path (every BOA php.ini keeps sendmail_path = /usr/sbin/sendmail -t -i, i.e. Postfix). So configuring msmtp alone changes nothing — PHP mail() and system mail still go through Postfix until an operator manually wires msmtp into the delivery path.

Relay vs. sites-allowed local sendmail — mutually exclusive

_smtp_check (lib/functions/system.sh.inc) sets the Postfix relayhost from _SMTP_RELAY_HOST only while /etc/boa/.allow.sendmail.cnf is absent. That file is the pre-existing box-wide control that re-opens /usr/sbin/sendmail for hosted-site use — without it the binary is chmod 750 root:allow-snail and sites cannot use local sendmail at all; with it, 755.

The gate is self-correcting both ways: if the allow file appears while a relayhost is already active, the next check reverts the relayhost line back to empty and reloads Postfix — direct (no-relay) delivery again. The rationale, per the gate's own comment: routing through the relay re-stamps mail to the relay's single sending domain, which is only safe while the host MTA carries solely backend/system mail. Once the allow file is present, hosted-site PHP mail() enters the same Postfix queue and would be re-stamped too.

Net effect: combining _SMTP_RELAY_HOST with sites-allowed local sendmail yields direct delivery for everything — if you need the relay, do not create the allow file. An empty relayhost despite _SMTP_RELAY_HOST being set is this gate working by design, not a lost setting.

Let's Encrypt renewal notices to clients

One class of BOA-originated transactional mail goes to your clients, not to you: the nightly maintenance run (the per-account owl.sh night worker, aegir/tools/system/night/10-account.sh) emails an account's client (_CLIENT_EMAIL from that account's /root/.<user>.octopus.cnf) an actionable notice when Let's Encrypt renewal keeps failing for their site(s) — update the domain's DNS, disable Encryption, or remove the dead alias.

  • On by default. Only the literal _LE_CLIENT_NOTIFY=NO disables the notices (quotes/spaces stripped, case-insensitive) — set it globally in /root/.barracuda.cnf or per account in /root/.<user>.octopus.cnf; the per-account value wins.
  • Throttled to once per 7 days per failing site via marker files <account>/log/ctrl/le-notify.<domain>.info (mtime-based; characters outside [a-zA-Z0-9._-] in the domain become _).
  • Skipped entirely when _CLIENT_EMAIL is empty or the local root alias.
  • The mail (sent via s-nail; subject: Action needed: HTTPS certificate renewal failed for one or more of your sites) carries a Reply-To of the account owner's address (_MY_OCTO_EMAIL, falling back to the server admin _ADMIN_EMAIL), set only when it is a real address containing @ — so a client's reply reaches a human instead of bouncing off the root@<host> envelope sender.

The worker reads only the account's own night log and that account's own _CLIENT_EMAIL, so a notice can never be cross-attributed to another account's client. For the full per-account LE failure reporting — the operator report, _INCIDENT_REPORT gating, ACME error mapping — see SSL operations.

Checking outbound mail volume

# Outbound mail queue (Postfix)
mailq

# Outbound mail log
tail -f /var/log/mail.log

If mailq grows, something is stuck or there is a delivery problem. If mail.log shows hundreds of sends per minute on a low-traffic host, you have a bulk-mail leak (probably an unintended Drupal notification flood).

Higher per-day mail volume

For self-hosted BOA you can configure higher thresholds — but the IP-reputation risk does not go away; use an ESP instead. For hosted-BOA, talk to omega8.cc support before any campaign.

Related