Panellicense

Plesk outbound mail throttling: stop abuse before Spamhaus does

Per-domain Postfix caps, PHP-to-port-25 lockdown, and Plesk's outgoing-mail controls — the layered defence that keeps one compromised mailbox from blacklisting the whole server.

7 min readUpdated 2026-05-17plesk · postfix · anti-spam · deliverability
schema: HowToschema: FAQPage

Plesk's default mail stack on Linux is Postfix plus Dovecot, and out of the box it will happily relay 200,000 messages from a single compromised customer mailbox before anyone notices. The "Limit outgoing email messages" feature exists, but on a fresh install every threshold is set to 0 (unlimited) and notifications are off. The first sign of trouble is usually a Spamhaus listing and an angry datacenter ticket.

This article is the Plesk equivalent of the cPanel/Exim throttling guide. For inbound reputation work — SPF, DKIM, DMARC, PTR — see the cPanel deliverability checklist; the DNS side is identical regardless of panel.

What you're actually defending against

Three things blow up shared Plesk mail servers, in roughly this order of frequency:

  1. A weak mailbox password gets brute-forced, the attacker authenticates against submission (port 587), and Postfix relays whatever they hand it.
  2. A vulnerable PHP app on a website calls mail() or opens a raw socket to 127.0.0.1:25. Postfix accepts it as a local submission with no auth and no rate limit.
  3. A reseller signs up a customer who is the abuse, deliberately blasts a list, then disappears with the chargeback.

Plesk's built-in controls cover (1) and (2) cleanly. (3) needs a notification policy and a billing-side suspension flow, which we cover at the end.

Set the global mail-server caps first

The global limits act as a backstop. Even if a service plan forgets to set a per-domain cap, the server-wide ceiling stops a runaway.

Go to Tools & Settings → Mail Server Settings (in the Mail group). Scroll to Limit on outgoing email messages. Set:

  • Maximum number of outgoing email messages by a domain: 300 per hour
  • Maximum number of outgoing email messages by a subscription: 1000 per hour
  • Maximum number of outgoing email messages from one email address: 100 per hour

These are starting points for a typical shared-hosting box. Transactional senders (SaaS apps, e-commerce stores during launches) will need their subscriptions overridden — better to start tight and raise on request than to discover the limits during an incident.

Below those fields, tick Enable notifications on exceeding the limit of outgoing mail messages and set the admin email. This is the early-warning system; without it the limits silently queue and you find out from a customer complaint.

Apply per-plan defaults

Server-wide limits stop the worst case. The day-to-day signal-to-noise comes from setting the right defaults per service plan.

Go to Service Plans, edit the plan, and on the Mail tab set the same three fields to the values appropriate for that tier. A "Starter" plan with 50/domain/hour is defensible. A "Business" plan might justify 500/domain/hour. Reseller plans should set limits at the reseller level — those values then cap what their sub-plans can set.

Existing subscriptions don't pick up changed plan defaults automatically. After editing, go to Subscriptions, filter by plan, select all, and click Synchronize to push the new limits down. Skipping this is the most common reason "I set the limit but it's not working" — the old, looser values stick to existing subscriptions until you sync.

Lock down PHP-to-port-25

This is the bigger lift and the one most operators skip. By default any PHP script on the server can open a socket to localhost:25 and inject mail with no authentication. Plesk runs PHP as the subscription's system user, which is good for forensics but doesn't stop the send.

The cleanest fix is to block local submissions from anything other than the Postfix submission daemon. Edit /etc/postfix/main.cf and add:

smtpd_client_restrictions =
    permit_mynetworks,
    check_client_access pcre:/etc/postfix/php_block.pcre,
    permit_sasl_authenticated,
    reject

Then create /etc/postfix/php_block.pcre:

/^127\.0\.0\.1$/    REJECT Use authenticated SMTP submission on port 587

Reload Postfix:

systemctl reload postfix

PHP mail() will now fail. Tell customers to switch to SMTP authentication via the PHPMailer or Symfony Mailer libraries pointed at localhost:587 with their mailbox credentials. Plesk's WordPress Toolkit ships an SMTP plugin you can mass-install across managed sites to ease the transition.

Tune submission for brute-force resistance

The submission port (587) is where stolen mailbox passwords get exercised. Two settings in /etc/postfix/master.cf close the loop. Find the submission line and ensure the options include:

submission inet n       -       n       -       -       smtpd
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o smtpd_sasl_authenticated_header=yes
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject_unauth_destination
  -o smtpd_sender_login_maps=hash:/var/spool/postfix/plesk/virtual_logins
  -o smtpd_sender_restrictions=reject_sender_login_mismatch,permit_sasl_authenticated,reject

smtpd_sender_login_maps and reject_sender_login_mismatch together stop a compromised account from spoofing the From: of a different domain on the same server — a common abuse pattern.

Pair this with Plesk's built-in fail2ban (Tools & Settings → IP Address Banning) and enable the plesk-postfix jail. Default thresholds are reasonable: 5 failed auths in 10 minutes = 1 hour ban. Drop to 3 attempts on busy servers.

When the queue is already on fire

Same workflow as Exim, different commands. Postfix queue triage:

mailq | tail -1                          # current queue depth
postqueue -p | awk '/^[A-F0-9]/ {print $7}' | sort | uniq -c | sort -rn | head

The second command groups queued mail by sender — the address at the top is almost always the compromised mailbox. Suspend it from Mail → Mail Accounts, change the password, then flush the bad sender's mail from the queue:

mailq | awk '/^[A-F0-9].*offender@example\.com/ {print $1}' | tr -d '*!' | \
    xargs -n1 -I{} postsuper -d {}

Don't postsuper -d ALL unless you've confirmed there's nothing legitimate queued — shared servers always have a few stuck messages from real customers.

Watch for it next time

The notification email from Plesk is fine but easy to miss. Two operational habits help:

  • Pipe Plesk's /var/log/plesk/panel.log and /var/log/maillog into your log aggregator (Loki, Splunk, or even a daily logwatch digest) with alerts on outgoing email limit exceeded and relay denied.
  • Run a daily cron that emails the top 10 outbound senders by message count. A long-time customer suddenly appearing at the top of the list is your earliest signal.

For more aggressive content scanning, Imunify Email adds outbound spam classification on top of Plesk's default SpamAssassin — useful on servers that host a mix of marketing and transactional senders, where simple rate limits will hit false positives.

Next steps

Where do I find Plesk's outgoing mail limits?+
Tools & Settings → Mail Server Settings, then scroll to 'Limit on outgoing email messages'. Per-plan defaults live under Service Plans → (plan) → Mail tab. Existing subscriptions need a manual Synchronize after you change plan defaults.
Why is Plesk still letting PHP send mail after I set per-mailbox limits?+
The mailbox limits only apply to authenticated submissions. PHP scripts using mail() inject directly via the local Postfix pickup service and bypass them. Block localhost:25 in smtpd_client_restrictions and require SMTP auth on port 587.
Does the outgoing-mail limit count internal recipients?+
Yes — every recipient counts, including mail between two mailboxes on the same Plesk server. A newsletter to 500 internal addresses uses 500 of the sender's hourly quota.
How do I find which mailbox is spamming on Plesk?+
Run postqueue -p | awk '/^[A-F0-9]/ {print $7}' | sort | uniq -c | sort -rn | head. The address at the top with the highest queued count is almost always the compromised one. Cross-check against /var/log/maillog for the original submission IP.
Can I exempt a transactional sender from the global limit?+
Yes. On the subscription, open Mail Settings and tick 'Override service plan settings', then raise the per-domain and per-address limits. Keep the global cap in place as a backstop — don't disable it just because one customer needs more headroom.
Does throttling apply on Plesk for Windows?+
Partly. Plesk for Windows uses MailEnable or IceWarp, and the 'Limit on outgoing email messages' UI exists but the enforcement layer differs. The PHP-to-port-25 lockdown described here is Linux-only; on Windows, configure equivalent restrictions in the mail server itself.
Switch in an afternoon

Switch from your current reseller — free.

We migrate active cPanel, Plesk, LiteSpeed and CloudLinux licenses from any reseller. We prorate the first month so you never pay twice, and your customers see zero downtime during the swap.