Skip to content
HackIndex logo

HackIndex

SMTP User Enumeration

3 min read Mar 29, 2026

SMTP user enumeration confirms which email addresses exist on the target mail server using the VRFY, EXPN, and RCPT TO commands. A confirmed user list enables targeted password spraying against OWA, SMTP submission, and other services. RCPT TO is the most reliable method — it works even when VRFY and EXPN are explicitly disabled, because recipient validation happens as a normal part of the mail flow. Run this after SMTP enumeration confirms which commands the server supports.

Check Which Methods Are Available

The EHLO response shows whether VRFY is advertised. EXPN and RCPT TO are always worth testing regardless:

┌──(kali㉿kali)-[~]
└─$ echo -e 'EHLO test\nQUIT' | nc -nv $TARGET_IP 25 | grep -iE 'vrfy|expn|auth'
250-VRFY
250-AUTH PLAIN LOGIN

Manual VRFY Testing

Test a few known accounts manually before running automated tooling to confirm response patterns:

┌──(kali㉿kali)-[~]
└─$ echo -e 'EHLO test\nVRFY admin\nVRFY root\nVRFY postmaster\nVRFY nonexistent123\nQUIT' | nc -nv $TARGET_IP 25
250 2.0.0 admin
550 5.1.1 <root>: Recipient address rejected
250 2.0.0 postmaster
550 5.1.1 <nonexistent123>: Recipient address rejected

250 confirms the user. 550 is a strong negative. 252 means the server won't verify but will accept the message — this is not a positive confirmation, do not treat it as one. Establish the positive and negative response patterns from a known-good and known-bad username before running bulk enumeration.

Manual RCPT TO Testing

When VRFY is disabled, RCPT TO still validates recipients. The server must confirm or deny the recipient before queuing the message:

┌──(kali㉿kali)-[~]
└─$ echo -e 'EHLO test\nMAIL FROM:<[email protected]>\nRCPT TO:<admin@$DOMAIN>\nRCPT TO:<nonexistent@$DOMAIN>\nQUIT' | nc -nv $TARGET_IP 25
250 2.1.5 Ok
550 5.1.1 <[email protected]>: Recipient address rejected: User unknown

Automated Enumeration with smtp-user-enum

Use RCPT mode first. It is the most reliable across different server configurations. Provide the domain with -D to append it to usernames from the wordlist:

┌──(kali㉿kali)-[~]
└─$ smtp-user-enum -M RCPT -U /usr/share/seclists/Usernames/top-usernames-shortlist.txt -D $DOMAIN -t $TARGET_IP -p 25
[*] Trying RCPT method...
[+] [email protected] exists
[+] [email protected] exists
[+] [email protected] exists
┌──(kali㉿kali)-[~]
└─$ smtp-user-enum -M VRFY -U /usr/share/seclists/Usernames/top-usernames-shortlist.txt -t $TARGET_IP -p 25
┌──(kali㉿kali)-[~]
└─$ smtp-user-enum -M EXPN -U /usr/share/seclists/Usernames/top-usernames-shortlist.txt -t $TARGET_IP -p 25

Wordlist Selection

Choose wordlists based on what you know about the target. Generic username lists work for initial discovery, but domain-specific lists based on naming conventions are more effective:

┌──(kali㉿kali)-[~]
└─$ # Generate firstname.lastname variants from a names list
┌──(kali㉿kali)-[~]
└─$ python3 -c "
names = [('john','smith'),('jane','doe'),('bob','jones')]
for f,l in names:
print(f'{f}.{l}@$DOMAIN')
print(f'{f[0]}{l}@$DOMAIN')
print(f'{f}_{l}@$DOMAIN')
" > /tmp/custom_users.txt
┌──(kali㉿kali)-[~]
└─$ smtp-user-enum -M RCPT -U /tmp/custom_users.txt -t $TARGET_IP -p 25

False Positive Filtering

Some servers accept all RCPT TO addresses regardless of whether the user exists — catch-all configurations. Detect this by testing a clearly random address and checking whether it also returns 250:

┌──(kali㉿kali)-[~]
└─$ echo -e 'EHLO test\nMAIL FROM:<[email protected]>\nRCPT TO:<xyzzy99999randomuser@$DOMAIN>\nQUIT' | nc -nv $TARGET_IP 25
250 2.1.5 Ok

A 250 for a clearly invalid address confirms catch-all configuration — RCPT TO enumeration produces only false positives on this server. Switch to VRFY if available, or rely on other sources for user discovery such as OSINT and LinkedIn scraping.

References