Discovering an email spam attack by mistake

On 14th May 2026, I logged onto my server to clear some disk space, only to find out that my mail server was under attack: an attacker got access to a mail account with weak credentials and sent spam from my domain.

My mail server was configured to use Linux system accounts instead of the commonly recommend virtual mailboxes. I created a user a while back called test with the password test for test reasons. Bots are trying to gain access to the mail server all the time by brute forcing usernames and passwords, and the attacker cracked these credentials during one of these attempts. Apart from sending spam, the attacker also managed to fill up my machine’s tiny little disk and cause chaos on my machine.

The immediate mitigations were to delete the test user and clear the mail queue, which brought the machine back to regular functionality. Then I started looking into the logs to see what actually happened and think about further mitigations.

Timeline

The story begins two days earlier on 12th May, when the attacker got access to the mail account for the first time.

2026-05-12T00:01:47.478629+00:00 mail postfix/submission/smtpd[32860]: connect from unknown[77.83.39.88]
2026-05-12T00:01:47.723271+00:00 mail postfix/submission/smtpd[32860]: B06C6757: client=unknown[77.83.39.88], sasl_method=PLAIN, sasl_username=test

Linux system accounts don’t have the domain name in it, so test is the valid username instead of test@orgnizedmess.net.

Its first attempt at sending an email didn’t work.

2026-05-12T00:01:47.745625+00:00 mail postfix/cleanup[33156]: B06C6757: message-id=<TIFJBWXP8TU4.RE5ZGIOEPGI01@win-4tti4dh7sgh>
2026-05-12T00:01:47.750603+00:00 mail postfix/qmgr[1337]: B06C6757: from=<test@mail.orgnizedmess.net>, size=549, nrcpt=1 (queue active)
2026-05-12T00:01:48.485223+00:00 mail postfix/smtp[33157]: B06C6757: to=<REDACTED@gmail.com>, relay=gmail-smtp-in.l.google.com[192.178.223.27]:25, delay=0.76, delays=0.03/0.03/0.13/0.56, dsn=5.7.26, status=bounced (host gmail-smtp-in.l.google.com[192.178.223.27] said: 550-5.7.26 Your email has been blocked because the sender is unauthenticated. 550-5.7.26 Gmail requires all senders to authenticate with either SPF or DKIM. 550-5.7.26  550-5.7.26  Authentication results: 550-5.7.26  DKIM = did not pass 550-5.7.26  SPF [mail.orgnizedmess.net] with ip: [176.126.245.29] = did not pass 550-5.7.26  550-5.7.26  For instructions on setting up authentication,
    go to 550 5.7.26  https://support.google.com/mail/answer/81126#authentication 5b1f17b1804b1-48e90667236si6532365e9.0 - gsmtp (in reply to end of DATA command)
)
2026-05-12T00:01:48.490975+00:00 mail postfix/bounce[33158]: B06C6757: sender non-delivery notification: 76B58119B
2026-05-12T00:01:48.491893+00:00 mail postfix/qmgr[1337]: B06C6757: removed

The email is bounced as the SPF and DKIM records have been configured to work for the root domain orgnizedmess.net. The attacker is attempting to send emails from the subdomain mail.orgnizedmess.net — the MX DNS record for this domain. Gmail is quite strict about these measures, so the response is expected.

When an email is bounced, a non-delivery email is generated for the sender with the error message and the original email is removed. Since the sender’s domain matches my domain, my mail server attempts to send a non-delivery email to itself.

2026-05-12T00:01:48.487211+00:00 mail postfix/cleanup[33156]: 76B58119B: message-id=<20260512000148.76B58119B@mail.orgnizedmess.net>
2026-05-12T00:01:48.490106+00:00 mail postfix/qmgr[1337]: 76B58119B: from=<>, size=3671, nrcpt=1 (queue active)
2026-05-12T00:01:48.554220+00:00 mail postfix/smtpd[33159]: connect from localhost[127.0.0.1]
2026-05-12T00:01:48.554622+00:00 mail postfix/smtp[33157]: warning: host mail.orgnizedmess.net[127.0.1.1]:25 greeted me with my own hostname mail.orgnizedmess.net
2026-05-12T00:01:48.555016+00:00 mail postfix/smtp[33157]: warning: host mail.orgnizedmess.net[127.0.1.1]:25 replied to HELO/EHLO with my own hostname mail.orgnizedmess.net
2026-05-12T00:01:48.558626+00:00 mail postfix/smtp[33157]: 76B58119B: to=<test@mail.orgnizedmess.net>, relay=mail.orgnizedmess.net[127.0.1.1]:25, delay=0.07, delays=0/0/0.06/0, dsn=5.4.6, status=bounced (mail for mail.orgnizedmess.net loops back to myself)
2026-05-12T00:01:48.560020+00:00 mail postfix/qmgr[1337]: 76B58119B: removed

The “loops back to myself” error message took me a while to understand, and turns out that this error is due to my mail server’s configuration. Postfix has a parameter to specify which domains the server is receiving mail for, which I have set to only the root domain. The subdomain isn’t mentioned there, so the mail server considers mail.orgnizedmess.net as an external domain. However, it sees that the IP address of that “external” domain resolves to its own domain, gets confused and bounces the email.

This particular attacker was surprisingly quiet for the rest of the day. I sent and received emails just fine on the 12th, and had no clue this was happening.

On 13th afternoon, another IP address from the same subnet logs into the test account and sends emails to different multiple addresses, this time to multiple email providers. Some of the emails got sent successfully, probably because certain providers don’t check for SPF/DKIM records that strictly.

2026-05-13T15:03:04.893972+00:00 mail postfix/submission/smtpd[46861]: DA2C11216: client=unknown[77.83.39.213], sasl_method=LOGIN, sasl_username=test
2026-05-13T15:03:04.924761+00:00 mail postfix/cleanup[46877]: DA2C11216: message-id=<20260513170302.10055872C2A66C40@mail.orgnizedmess.net>
2026-05-13T15:03:04.929626+00:00 mail postfix/qmgr[1337]: DA2C11216: from=<test@mail.orgnizedmess.net>, size=3410, nrcpt=1 (queue active)
2026-05-13T15:03:11.028898+00:00 mail postfix/smtp[46880]: DA2C11216: to=<REDACTED@yahoo.com>, relay=mta7.am0.yahoodns.net[98.136.96.77]:25, delay=6.1, delays=0.05/0.04/1.3/4.8, dsn=2.0.0, status=sent (250 ok dirdel)
2026-05-13T15:03:11.030171+00:00 mail postfix/qmgr[1337]: DA2C11216: removed

The attacker did this sending email to different email providers one more time (not sure why) and then disappeared.

Within a few minutes, there were login attempts to test from a fourth IP address, and this time the destination addresses were a bunch of addresses for whom sending worked in the previous attempt.

2026-05-13T16:09:30.054888+00:00 mail postfix/submission/smtpd[47229]: 0D3E89EF: client=unknown[165.154.236.241], sasl_method=LOGIN, sasl_username=test
2026-05-13T16:09:30.164140+00:00 mail postfix/submission/smtpd[47217]: 27BD7118C: client=unknown[165.154.236.241], sasl_method=LOGIN, sasl_username=test
2026-05-13T16:09:30.198120+00:00 mail postfix/submission/smtpd[47228]: 2FFF2119B: client=unknown[165.154.236.241], sasl_method=LOGIN, sasl_username=test
2026-05-13T16:09:30.256079+00:00 mail postfix/submission/smtpd[47235]: 3E33C11CF: client=unknown[165.154.236.241], sasl_method=LOGIN, sasl_username=test
2026-05-13T16:09:30.281181+00:00 mail postfix/submission/smtpd[47227]: 441B211D9: client=unknown[165.154.236.241], sasl_method=LOGIN, sasl_username=test
2026-05-13T16:09:30.321127+00:00 mail postfix/submission/smtpd[47230]: 4E04511E6: client=unknown[165.154.236.241], sasl_method=LOGIN, sasl_username=test
2026-05-13T16:09:30.337046+00:00 mail postfix/submission/smtpd[47231]: 5174D120D: client=unknown[165.154.236.241], sasl_method=LOGIN, sasl_username=test
2026-05-13T16:09:30.349869+00:00 mail postfix/submission/smtpd[47233]: 5529E1216: client=unknown[165.154.236.241], sasl_method=LOGIN, sasl_username=test
2026-05-13T16:09:30.367046+00:00 mail postfix/submission/smtpd[47234]: 593441217: client=unknown[165.154.236.241], sasl_method=LOGIN, sasl_username=test
2026-05-13T16:09:30.378283+00:00 mail postfix/submission/smtpd[47232]: 5C11D122C: client=unknown[165.154.236.241], sasl_method=LOGIN, sasl_username=test

This sending was quite aggressive: the statistics show about 160 connections/minute, or 10 connections/second. One connection sends one email, so this totals to 10 emails/second or 160 emails/minute.

2026-05-13T16:14:11.568275+00:00 mail postfix/anvil[47164]: statistics: max connection rate 160/60s for (submission:165.154.236.241) at May 13 16:10:32
2026-05-13T16:14:11.570455+00:00 mail postfix/anvil[47164]: statistics: max connection count 10 for (submission:165.154.236.241) at May 13 16:09:27

Shortly after, Yahoo’s servers started detecting my machine as spam.

2026-05-13T16:16:20.185243+00:00 mail postfix/smtp[47684]: 93023120D: host mta5.am0.yahoodns.net[98.136.96.75] said: 421 4.7.0 [TSS05] Messages from REDACTED temporarily deferred due to unexpected volume or user complaints - 4.16.55.1; see https://postmaster.yahooinc.com/error-codes (in reply to MAIL FROM command)

Deferred mails get added to my server’s mail queue to be sent again later. The attacker continued to send emails, the emails kept getting detected as spam and added to the mail queue. My server would try to send them again and they would be deferred again due to spam detection. Within a few hours, my machine’s tiny little disk started to run out of space.

2026-05-13T22:41:12.161019+00:00 mail postfix/submission/smtpd[91838]: NOQUEUE: reject: MAIL from unknown[165.154.236.241]: 452 4.3.1 Insufficient system storage; proto=ESMTP helo=<[165.154.236.241]>
2026-05-13T22:41:12.161095+00:00 mail postfix/submission/smtpd[91838]: warning: not enough free space in mail queue: 37072896 bytes < 1.5*message size limit

This was a warning message, so sending was still being attempted. The byte count indicating free space started to get lower and lower, until eventually, there was no space left.

2026-05-13T22:50:33.910731+00:00 mail postfix/bounce[93254]: fatal: append file defer F29D32CAAA: No space left on device

The attacker finally stopped sending spam later that night, as connections would get closed abruptly due to no space.

2026-05-14T01:19:11.484255+00:00 mail postfix/submission/smtpd[105587]: connect from unknown[165.154.236.241]
2026-05-14T01:19:12.697735+00:00 mail postfix/cleanup[105761]: 996F92C3E5: message-id=<20260514011911.996F92C3E5@mail.orgnizedmess.net>
2026-05-14T01:19:12.699963+00:00 mail postfix/cleanup[105761]: warning: 996F92C3E5: write queue file: No space left on device
2026-05-14T01:19:12.702248+00:00 mail postfix/cleanup[105761]: warning: mail_stream_cleanup: close error
2026-05-14T01:19:12.704843+00:00 mail postfix/submission/smtpd[105753]: disconnect from unknown[165.154.236.241] ehlo=2 starttls=1 auth=1 mail=0/1 quit=1 commands=5/6

There are no logs between the ones above and 14th evening — that’s when I logged onto the machine to clear disk space in some usual areas (old kernels and related headers). Looks like that was just enough space for Postfix to start working again and write more logs. And what did it decide to do? It made an attempt to send all of the emails in the mail queue…at once.

2026-05-14T01:19:14.544810+00:00 mail postfix/qmgr[104607]: 211C733C5F: from=<test@mail.orgnizedmess.net>, size=1706, nrcpt=1 (queue active)
2026-05-14T19:44:41.698569+00:00 mail postfix/qmgr[159741]: D07F527648: from=<test@mail.orgnizedmess.net>, size=1700, nrcpt=1 (queue active)
2026-05-14T19:44:41.702853+00:00 mail postfix/qmgr[159741]: 05DF432BB8: from=<test@mail.orgnizedmess.net>, size=1704, nrcpt=1 (queue active)
2026-05-14T19:44:41.703239+00:00 mail postfix/qmgr[159741]: C4AA4235E2: from=<test@mail.orgnizedmess.net>, size=1712, nrcpt=1 (queue active)
2026-05-14T19:44:41.704507+00:00 mail postfix/qmgr[159741]: 064942BFC3: from=<test@mail.orgnizedmess.net>, size=1702, nrcpt=1 (queue active)
2026-05-14T19:44:41.706471+00:00 mail postfix/qmgr[159741]: 42AC72A9C6: from=<test@mail.orgnizedmess.net>, size=1702, nrcpt=1 (queue active)
2026-05-14T19:44:41.707180+00:00 mail postfix/qmgr[159741]: 058381FB52: from=<test@mail.orgnizedmess.net>, size=1706, nrcpt=1 (queue active)
2026-05-14T19:44:41.708112+00:00 mail postfix/qmgr[159741]: A876720F72: from=<test@mail.orgnizedmess.net>, size=1710, nrcpt=1 (queue active)
...

My initial attempts at clearing disk space didn’t make much of a difference, neither do I remember seeing anything mail related stand out when looking for files taking up space. Then I ran htop to see if something was up. It reported 30-40% of CPU usage as compared to the usual 1-2%, an observation that matches the above logs as Postfix struggled trying to send all these emails.

I checked the mail queue, and it started printing lines endlessly, more than I could keep up with. I finally looked into the logs, where I saw these messages being sent from test@mail.orgnizedmess.net. I started by deleting individual mails with the specific FROM address, but that took too long. So I deleted the entire queue at once. I also deleted the test user to prevent further attacks.

In hindsight, I wish I would have looked at the contents one of the emails to know what got sent, but panic got the better of me.

Summary

Now for some numbers. I initially used pflogsumm for the analysis, however I ended up making my own little script as pflogsumm didn’t have options to filter for FROM addresses or date ranges. The script runs on a truncated version of /var/log/mail.log, which contains logs only for the duration of the attack (12th-14th May).

$ python3 status.py
  68354   total
   1654   sent
   6465   bounced
   9685   rejected
  50533   deferred
     17   unknown

  50543   mail queue count before deletion

Nearly 70000 emails were attempted to be sent by the attacker…yikes. The deferred emails make up a major chunk of this list, which explains the disk space issues.

Some emails were bounced due to SPF/DKIM restrictions as seen with Gmail earlier, or due to an invalid destination address.

2026-05-13T16:09:32.959057+00:00 mail postfix/smtp[47259]: 0D3E89EF: to=<REDACTED@rocketmail.com>, relay=mta7.am0.yahoodns.net[67.195.228.106]:25, delay=3.1, delays=0.73/0.03/1.3/0.98, dsn=5.0.0, status=bounced (host mta7.am0.yahoodns.net[67.195.228.106] said: 552 1 Requested mail action aborted, mailbox not found (in reply to end of DATA command))

The unknown status emails all have a similar pattern: they got added to the queue, but there are no sending attempts.

2026-05-14T01:07:38.504094+00:00 mail postfix/submission/smtpd[104320]: 7AF2322D6A: client=unknown[165.154.236.241], sasl_method=LOGIN, sasl_username=test
2026-05-14T01:07:39.049364+00:00 mail postfix/cleanup[104511]: 7AF2322D6A: message-id=<20260514090734.72682B944F72F1FE@mail.orgnizedmess.net>
2026-05-14T01:07:56.548228+00:00 mail postfix/qmgr[104607]: 7AF2322D6A: from=<test@mail.orgnizedmess.net>, size=1702, nrcpt=1 (queue active)
2026-05-14T19:49:07.166301+00:00 mail postfix/qmgr[159741]: 7AF2322D6A: from=<test@mail.orgnizedmess.net>, size=1702, nrcpt=1 (queue active)
2026-05-14T20:00:16.888781+00:00 mail postfix/qmgr[1160]: 7AF2322D6A: from=<test@mail.orgnizedmess.net>, size=1702, nrcpt=1 (queue active)
2026-05-14T20:12:18.752262+00:00 mail postfix/postsuper[60123]: 7AF2322D6A: removed
2026-05-14T20:12:18.781551+00:00 mail postfix/smtp[58922]: warning: open active 7AF2322D6A: No such file or directory

My guess is that the because the queue was so big by this point, their turn for sending never came. Eventually, these emails were deleted when I emptied the queue.

Finally, I wanted to know the number emails I deleted from the queue. It should be a total of the deferred and unknown status emails, and the amount from the script nearly matches that amount. The difference in values might be due to the incomplete logs as some lines got overwritten, but I haven’t investigated this closely as this post is getting too long and I really want to get this post out there.

Reflections

In the case of using system accounts, the login username is just the username and not the full email address, so there is no distinction between test@orgnizedmess.net and test@mail.orgnizedmess.net. This combined with weak credentials made my machine an easy target. I figured that my current Postfix configuration would prevent this situation, but turns out Postfix worked in ways that I didn’t expect it to.

I haven’t had major troubles sending emails yet and I haven’t been kicked out by my hosting provider, so luckily the damage was minimal while also serving as a great learning opportunity.

Here are some takeaways of longer term things I’d like to work on based on this attack:

Notes on setting up a mail server

As part of my public homelab setup, one of the services I configured was a mail server! I got started with around a month ago, and have been running a bare minimum setup for a week. Here are some notes about the configuration process.

Finding the right infrastructure

Most providers and ISPs block port 25 traffic due to it being an easy target for spam. It makes sense to do so, as even one machine sending spam would put the entire network on a blocklist, unable to send email.

Some providers have an option to request to unblock the port. Vultr is one such provider I heard of, so I started by hosting my website there, and submitted an unblock request within a few days that was eventually rejected.

That left me with two options:

  1. Switch to a provider that allows SMTP traffic
  2. Use an external service called a SMTP relay to handle sending and self-host receiving email.

The second option is the approach I saw recommended most often, as it delegates the responsbility of maintaining sender reputation while letting you store email on a server you control. I started with this option on the Vultr VPS, but eventually went with the first option.

In hindsight, I could have easily stuck with the Vultr VPS, and this was an important lesson about firewalls. Firewalls have separate rules for incoming and outgoing traffic, and port 25 is only blocked for outgoing traffic by most providers. Incoming traffic at port 25 is allowed, so receiving mail works fine. I didn’t test this and assumed that port 25 was blocked in either direction, which led to the switch to my current provider.

An unintentional advantage of this switch is that I’m now responsible for handling both sending and receiving, which has been a better learning experience. Whether this remains an advantage or not - time will tell.

Finding the right learning material

There isn’t a shortage of tutorials out there, but none of them went into details behind the “why”. While searching about one of the aspects, I came across a series of posts titled Setting up Postfix and Dovecot Slowly and Properly by brokker.net, which is exactly what I needed! It takes you through the setup in small increments, with each step ending with a working setup you can test, which I really liked. This series gave me the foundation I needed, and from here I could decide which aspects I wanted to implement.

Another setup guide I found useful was Install and Configure a Secure Mail Server on Debian with Postfix and Dovecot by std.rocks. It’s a newer, concise guide, and especially useful after having gone through the series. In particular, I followed its instructions for setting up OpenDKIM, SPF and DMARC much earlier than mentioned in the series, as these aspects seem to have gone from “nice to have” to “absolutely required” over time for sending to work, especially when sending emails to Gmail addresses.

Configuring a test server

I already had this domain hosted elsewhere and have been sending and receiving mails at this domain. I initially started by switching the primary mail server to the test server by changing the DNS record. However, the setup was taking me a while as I was taking time to understand and test the various aspects. That would mean I may or may not receive emails sent during that time, and needed a test setup.

The test setup that worked was a secondary mail server - mx.orgnizedmess.net - that receives emails at a subdomain instead of the root domain. I would send test emails to user@mx.orgnizedmess.net instead of user@orgnizedmess.net.

This was not as straightforward as I thought, as parts of the configuration varied for subdomains, that wasn’t as obvious to me:

Where the lines between different services get blurred

There are two main servers - SMTP (Postfix) and IMAP (Dovecot). Postfix handles sending and receiving of emails (aka the MTA or Mail Transfer Agent), and Dovecot handles mailboxes for different users and lets me access mail in a mail client (aka the MUA or Mail User Agent). Any setup beyond is where the services started to rely on each other, and also where I got confused the most.

Wow that’s a lot of acronyms.

Towards a public homelab

I haven’t been able to make progress on my homelab. The setup was all local and I was mostly working on my own, so it wasn’t as fun to work on after a point. I also started overthinking parts of the setup, which is ironical since the idea of a lab is to experiment. Then I started seeing discussions around self-hosting email, and that got me thinking about how I could reframe the project.

My current public infrastructure is a combination of three services - a web server, DNS and email - which overlapped with ideas I had for the homelab. Being able to manage these services myself sounded like a fun challenge - and suddenly the project became exciting to work on again!

I was sure that I wanted to host on a Virtual Private Server or VPS - I wasn’t ready to host a machine at home just yet. A VPS lets me configure a Linux machine the way I would at home, but without me having to deal with public Internet traffic at home. The setup is also not tied to any specific platform, so I can move to a Linux machine on another provider or switch to a home-based setup whenever required.

I have hosted my website on a small VPS before and know that it can handle the current level of traffic, so I decided to stick with the same specs and see if it could handle DNS and email too. After some trial and error with providers, I settled on the smallest VPS offering from Mythic Beasts - 1 CPU, 1GB RAM and a 5GB SSD. It is currently hosting this website, a mailserver and an authoritative DNS server for this domain, and it seems to be running fine so far.

The original homelab setup is still useful as it has more resources than the public machine does. This makes it useful for running multiple virtual machines to simulate networks, or for ideas that require me to interact with lower levels of the network stack or the hardware.

A simple website blocker

I have been visiting some websites out of habit that don’t make me feel great, so I started looking for website blocker apps. In the process of doing so, an easier solution came to mind - editing the /etc/hosts file.

I opened /etc/hosts, and set the IP address for the domain I want to block (LinkedIn in this case) to 0.0.0.0. The address isn’t a valid destination address, so the browser fails to connect after the domain is resolved.

0.0.0.0 www.linkedin.com linkedin.com

I can append other domains to the above line after the IP address, or add another line with the same address and another domain if this line starts to get too long.

I flushed the DNS cache on my machine and after a while, LinkedIn doesn’t load anymore! Mission accomplished!

A new internet home

This site has moved from pjg1.site to orgnizedmess.net!

I’ve been thinking of making this move from at least a year, and a recent price hike for the previous domain ($26.24 -> $28.84) finally made me switch. The new name comes from a username I’ve used previously and liked, and it costs me nearly half the price ($12.52), a win-win!

I have set up a permanent redirect from the old domain to the new one. I won’t be renewing the old domain any further, so the redirects will work till July. Those subscribed to the site via RSS can re-subscribe using the new URL by then to continue receiving posts.