Refusing mail with SMTP 521 and systemd

When an email message can’t be delivered, most mail servers will store it and try again later, usually for a number of days. This is very useful when the receiving mail server is temporarily unreachable, busy, or otherwise unavailable. If that happens, the email will simply be delayed for a while instead of getting lost entirely.

However, it’s hard for the sending mail server to decide whether port 25 on the server it’s trying to reach is just temporarily down or instead permanently down. It might be that the receiving server is just not interested in email. Servers increasingly get a single role; some machines don’t (and won’t ever) accept any email.

If that’s the case, having the sending party try, try, and try again would be a (small) waste of resources on their part. It would be better if we could somehow signal that the server is not interested in mail, thank you very much.

There is an RFC that has a SMTP reply code to do just that: RFC 7504, which defines code 521 to “indicate that the host does not accept mail under any circumstances.” While you could probably configure a general-purpose MTA to respond with 521, running a mail server just to refuse mail would be a bit silly. Here’s a trick that uses systemd’s socket activation feature to create a dummy SMTP server that never accepts anything.

First, you’ll need a socket file, describing which port you want your fake SMTP server to listen on. We want a stream (TCP) socket on port 25, and we want systemd to accept connections for us.

# /etc/systemd/system/smtp521.socket 

[Socket]
ListenStream=25
Accept=yes

[Install]
WantedBy=sockets.target

Next, you’ll need to give systemd something to start when someone connects, using a service file. Our dummy server sends out the 521, waits for the client to QUIT, then immediately says goodbye.

# /etc/systemd/system/smtp521@.service

[Service]
ExecStart=-/usr/bin/sh -c 'echo -ne "521 $(hostname -f) does not accept mail\r\n"; read; echo -ne "221 $(hostname -f) closing connection\r\n"'
StandardInput=socket
User=nobody

Start (and, if you want, enable) the socket with systemctl and try it out:

$ swaks --to some@example.com --server localhost
=== Trying localhost:25...
=== Connected to localhost.
<** 521 an.example.org does not accept mail
 -> QUIT
<-  221 an.example.org closing connection
=== Connection closed with remote host.

And there you go, a dummy SMTP server in three lines of shell scripting, with a little help from systemd.

Thanks for reading! If you have any questions, comments or corrections, feel free to shoot me an email.