email-server-diagnostics — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited email-server-diagnostics (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Perform a comprehensive diagnostic analysis of a self-hosted email service. Identify misconfigurations, missing records, and security issues that affect deliverability and security, then produce a clear report with prioritized recommendations.
Before running checks, establish:
example.com)mail.example.com)If not all provided, infer from DNS: MX → hostname → A → IP. Ask for the rest.
Run external checks (1-5) first — they need no server access. Internal checks (6) require SSH.
For each mail domain, check every record below using dig.
| Record | Lookup | What to verify |
|---|---|---|
| MX | dig MX <domain> +short | Points to correct hostname; priority reasonable; no stale entries |
| A / AAAA | dig A <hostname> + dig AAAA <hostname> | Resolves to expected IP; if AAAA exists, IPv6 must be fully configured |
| SPF | dig TXT <domain> +short | Has v=spf1; includes server IP or MX; ends -all or ~all; exactly ONE SPF record (multiple = error) |
| DKIM | dig TXT <selector>._domainkey.<domain> | Valid public key; try selectors: dkim, default, mail, s1, selector1, selector2, k1 |
| DMARC | dig TXT _dmarc.<domain> | v=DMARC1; policy quarantine or reject for production; has rua= for reporting |
| rDNS (PTR) | dig -x <ip> +short | Matches mail hostname exactly |
| Forward-confirmed rDNS | PTR → A lookup | PTR hostname must resolve back to the original IP |
| MTA-STS | dig TXT _mta-sts.<domain> + curl https://mta-sts.<domain>/.well-known/mta-sts.txt | TXT has v=STSv1; id=...; policy file accessible over HTTPS |
| TLSRPT | dig TXT _smtp._tls.<domain> | Has v=TLSRPTv1; rua=mailto:... |
| DANE/TLSA | dig TLSA _25._tcp.<hostname> | If DNSSEC enabled, TLSA record should exist (usage 3, selector 1, type 1 recommended) |
| BIMI | dig TXT default._bimi.<domain> | Optional; requires DMARC p=reject/quarantine with pct=100 |
| Autodiscover | dig A autodiscover.<domain> + dig A autoconfig.<domain> | Records exist for mail client auto-configuration |
| SRV | dig SRV _imaps._tcp.<domain>, _submission._tcp.<domain>, etc. | Service records for IMAP, SMTP, CalDAV, CardDAV |
Also check for stale records: old provider DKIM CNAMEs (e.g., gm1._domainkey → gandimail.net), conflicting SPF records, orphaned MX entries.
#### SPF Deep Validation
SPF has strict limits that are almost never checked manually but cause silent failures:
include, a, mx, redirect, exists mechanisms recursively. Exceeding 10 = PermError = SPF fails. # To count, recursively resolve each include and count mechanisms
dig TXT <domain> +short # start here, then follow each includeinclude: references to decommissioned services.+all or ?all (too permissive)ptr mechanisma and mx mechanisms when they add no value (wastes DNS lookups)#### DKIM Validation
t=y (testing mode) is still set in production.jan2025) indicate good rotation practice.Check certs on all mail protocols. For each, verify: not self-signed, not expired, correct CN/SAN, chain complete.
# HTTPS (web UI)
echo | openssl s_client -connect <ip>:443 -servername <hostname> 2>/dev/null | \
openssl x509 -noout -subject -issuer -dates -ext subjectAltName
# IMAPS
echo | openssl s_client -connect <ip>:993 -servername <hostname> 2>/dev/null | \
openssl x509 -noout -subject -issuer -dates
# SMTPS
echo | openssl s_client -connect <ip>:465 -servername <hostname> 2>/dev/null | \
openssl x509 -noout -subject -issuer -dates
# SMTP STARTTLS (port 25)
echo | openssl s_client -connect <ip>:25 -starttls smtp -servername <hostname> 2>/dev/null | \
openssl x509 -noout -subject -issuer -dates
# Submission STARTTLS (port 587)
echo | openssl s_client -connect <ip>:587 -starttls smtp -servername <hostname> 2>/dev/null | \
openssl x509 -noout -subject -issuer -dates#### TLS Protocol Version Check
Flag deprecated protocols. Minimum acceptable is TLS 1.2.
# Check if TLS 1.0/1.1 still accepted (should NOT be)
openssl s_client -connect <ip>:25 -starttls smtp -tls1 2>&1 | grep "Protocol"
openssl s_client -connect <ip>:25 -starttls smtp -tls1_1 2>&1 | grep "Protocol"Flag: self-signed certs, expired certs, wrong CN, mismatched certs across protocols, TLS < 1.2 still enabled.
Test all standard ports:
| Port | Protocol | Purpose |
|---|---|---|
| 25 | SMTP | Incoming mail |
| 80 | HTTP | Web UI, ACME challenges |
| 110 | POP3 | Mail retrieval (legacy) |
| 143 | IMAP | Mail retrieval |
| 443 | HTTPS | Web UI, autodiscover |
| 465 | SMTPS | Submission (implicit TLS) |
| 587 | Submission | Submission (STARTTLS) |
| 993 | IMAPS | Secure IMAP |
| 995 | POP3S | Secure POP3 |
| 4190 | Sieve | Mail filtering |
nc -z -w5 <ip> <port> && echo "open" || echo "closed"SMTP banner check (port 25):
echo "EHLO test" | nc -w5 <ip> 25Verify: correct hostname in banner, STARTTLS advertised, 250 response codes.
HELO hostname consistency: The SMTP banner hostname should match the PTR record, which should match the A record. This three-way match (forward-confirmed reverse DNS) is critical for deliverability.
Check the server IP against major DNSBLs. A listing on any of these significantly impacts deliverability.
# Reverse the IP octets for DNSBL query
# For IP 1.2.3.4, query 4.3.2.1.<dnsbl-zone>
# NXDOMAIN = clean; any A record (127.0.0.x) = listed
IP="<server-ip>"
REV=$(echo $IP | awk -F. '{print $4"."$3"."$2"."$1}')
for bl in zen.spamhaus.org b.barracudacentral.org bl.spamcop.net dnsbl.sorbs.net; do
result=$(dig +short ${REV}.${bl} 2>/dev/null)
if [ -z "$result" ]; then echo "$bl: CLEAN"
else echo "$bl: LISTED ($result)"; fi
done
# Domain blacklists
for bl in dbl.spamhaus.org multi.surbl.org multi.uribl.com; do
result=$(dig +short <domain>.${bl} 2>/dev/null)
if [ -z "$result" ]; then echo "$bl: CLEAN"
else echo "$bl: LISTED ($result)"; fi
doneAlso check IPv6 if AAAA records exist (IPv6 has separate reputation from IPv4).
Verify the server rejects relay attempts from unauthenticated sources. An open relay will get blacklisted very quickly.
# Connect from an external host without authentication and try to relay
# This should be REJECTED
(echo "EHLO test"; sleep 1; echo "MAIL FROM:<[email protected]>"; sleep 1; echo "RCPT TO:<[email protected]>"; sleep 1; echo "QUIT") | nc -w10 <ip> 25Expected: 554 or 550 reject on the RCPT TO command (relay denied). If you get 250 OK on RCPT TO for an external recipient, the server is an open relay — this is CRITICAL.
Adapt to the specific mail software. Database credentials can usually be found in the main config file.
#### Mailcow
# Key config values from mailcow.conf
grep -E "^(MAILCOW_HOSTNAME|SKIP_LETS_ENCRYPT|ENABLE_IPV6|ACL_ANYONE|HTTP_REDIRECT)" \
/opt/mailcow-dockerized/mailcow.conf
# Extract DB credentials
DBUSER=$(grep ^DBUSER /opt/mailcow-dockerized/mailcow.conf | cut -d= -f2)
DBPASS=$(grep ^DBPASS /opt/mailcow-dockerized/mailcow.conf | cut -d= -f2)
REDIS_PASS=$(grep ^REDISPASS /opt/mailcow-dockerized/mailcow.conf | cut -d= -f2)
# Domains
cd /opt/mailcow-dockerized
docker compose exec -T mysql-mailcow mysql -u$DBUSER -p$DBPASS mailcow \
-e "SELECT domain,active,backupmx FROM domain;"
# Mailboxes
docker compose exec -T mysql-mailcow mysql -u$DBUSER -p$DBPASS mailcow \
-e "SELECT username,domain,active,quota FROM mailbox;"
# Aliases
docker compose exec -T mysql-mailcow mysql -u$DBUSER -p$DBPASS mailcow \
-e "SELECT address,goto,active FROM alias WHERE address NOT LIKE '@%';"
# DKIM keys (stored in Redis)
docker compose exec -T redis-mailcow redis-cli -a "$REDIS_PASS" HGETALL DKIM_SELECTORS
docker compose exec -T redis-mailcow redis-cli -a "$REDIS_PASS" HKEYS DKIM_PRIV_KEYS
# ACME / Let's Encrypt status
docker compose logs acme-mailcow --tail 30
# Container health
docker compose ps --format "table {{.Name}}\t{{.Status}}"
# Postfix config highlights
docker compose exec -T postfix-mailcow postconf -n | \
grep -E "(myhostname|relayhost|smtpd_tls|smtpd_relay_restrictions)"
# Mail queue depth
docker compose exec -T postfix-mailcow postqueue -p | tail -1
# Rspamd stats
docker compose exec -T rspamd-mailcow rspamc stat 2>/dev/null | head -20#### Generic Postfix/Dovecot
postconf -n | grep -E "(myhostname|mydestination|relay|smtpd_tls|smtp_tls|smtpd_relay)"
doveconf -n | grep -E "(ssl|auth_mechanisms|mail_location)"
postqueue -p | tail -1 # queue depth#### Internal checks to verify:
myhostname matches DNS and rDNSsmtpd_relay_restrictions contains reject_unauth_destination)These requirements are now enforced with permanent rejections. Check compliance for domains sending to Gmail, Yahoo, or Outlook.com.
All senders must have:
Bulk senders (>5,000 emails/day) must additionally have:
p=none and alignment passMicrosoft Outlook (May 2025+):
Flag any non-compliance as WARNING or CRITICAL depending on sending volume.
Only if the mail hostname has an AAAA record. Having a partially configured IPv6 is worse than having none.
AAAA=$(dig AAAA <hostname> +short)
if [ -n "$AAAA" ]; then
echo "IPv6: $AAAA"
# Must have IPv6 PTR
dig -x $AAAA +short # should return the hostname
# Must be in SPF (ip6: mechanism)
dig TXT <domain> +short | grep -o "ip6:[^ ]*"
# Check IPv6 blacklists separately
fiIf AAAA exists but PTR is missing or SPF doesn't include it → CRITICAL (Gmail rejects immediately).
## <domain> Email Server Diagnostic Report
### Server Overview
| Item | Value |
|---|---|
| Mail hostname | ... |
| Public IP | ... |
| rDNS (PTR) | ... |
| Server software | ... |
| Services status | X/Y running |
### Mailboxes & Aliases
(table of accounts and forwarding rules)
### DNS Records
| Record | Value | Status |
|---|---|---|
(OK / WARNING / MISSING / ERROR for each)
### SPF Analysis
- Record: `v=spf1 ...`
- DNS lookups used: X/10
- Void lookups: X/2
- Issues: (if any)
### DKIM Analysis
- Selector: ...
- Key length: ... bits
- Status: ...
### TLS Certificates
| Protocol | Port | Issuer | Expires | TLS Version | Status |
|---|---|---|---|---|---|
### Port Connectivity
| Port | Protocol | Status |
|---|---|---|
### Blacklist Status
| Blacklist | Status |
|---|---|
(CLEAN or LISTED for each)
### Compliance: Google/Yahoo/Microsoft Sender Requirements
(checklist with pass/fail for each requirement)
### Issues Found
1. **CRITICAL** — blocks delivery or causes rejection
2. **WARNING** — degrades deliverability or security
3. **INFO** — best-practice recommendations
### Recommended Actions
(numbered list, priority order, with specific commands or steps)CRITICAL (mail delivery blocked):
WARNING (deliverability degraded):
~all with DMARC p=reject (inconsistent)p=none in productionINFO (best practices):
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.