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:
- A weak mailbox password gets brute-forced, the attacker authenticates against submission (port 587), and Postfix relays whatever they hand it.
- A vulnerable PHP app on a website calls
mail()or opens a raw socket to127.0.0.1:25. Postfix accepts it as a local submission with no auth and no rate limit. - 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:
300per hour - Maximum number of outgoing email messages by a subscription:
1000per hour - Maximum number of outgoing email messages from one email address:
100per 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.logand/var/log/mailloginto your log aggregator (Loki, Splunk, or even a daily logwatch digest) with alerts onoutgoing email limit exceededandrelay 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
- cPanel Exim outbound throttling — the same defence pattern on the other panel
- Plesk ModSecurity whitelist rules — closes the PHP-app-compromise side of the threat
- Imunify360 behind Cloudflare — get the real attacker IP into your fail2ban jails