Are these emails valid? Link to heading
I have a list of about 100K emails. Before I just start sending them off I wanted to check if they are valid. I decided to check their domain names to see if they have MX records at all.
Here is the usage example:
# Usage:
# ./checkmx.sh [-p N] [@dnsserver] [file]
#
# Examples:
# ./checkmx.sh domains.txt
# ./checkmx.sh -p 10 @8.8.8.8 domains.txt
# cat domains.txt | ./checkmx.sh @1.1.1.1
#
# Output:
# stdout = domains that HAVE MX records
# stderr = domains that LACK MX records
Now I was an idiot and forgot to point it at 8.8.8.8
or 1.1.1.1
so my name server was the first hop… but it riped through about 20k domains in a few mins.
I ran it redirecting the different outputs like this:
$ ./checkmx.sh domains.txt > domains_yes_mx.txt 2> domains_no_mx.txt
Instead of:
$ ./checkmx.sh @8.8.8.8 domains.txt > domains_yes_mx.txt 2> domains_no_mx.txt
In case it helps someone else… enjoy.
#!/usr/bin/env bash
# checkmx.sh
#
# Usage:
# ./checkmx.sh [-p N] [@dnsserver] [file]
#
# Examples:
# ./checkmx.sh domains.txt
# ./checkmx.sh -p 10 @8.8.8.8 domains.txt
# cat domains.txt | ./checkmx.sh @1.1.1.1
#
# Output:
# stdout = domains that HAVE MX records
# stderr = domains that LACK MX records
set -euo pipefail
dns_server=""
file=""
parallelism=4 # default parallel jobs
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-p)
if [[ $# -lt 2 ]]; then
echo "Error: -p requires a number" >&2
exit 1
fi
parallelism="$2"
shift 2
;;
@*)
dns_server="$1"
shift
;;
-*)
echo "Unknown option: $1" >&2
exit 1
;;
*)
file="$1"
shift
;;
esac
done
# Input: file or stdin
if [[ -n "$file" ]]; then
input=$(cat "$file")
else
input=$(cat -)
fi
# Function to check a single domain
check_domain() {
local domain="$1"
local dns_server="$2"
[[ -z "$domain" ]] && return 0
# Query MX, suppress dig warnings/errors
if dig $dns_server +short MX "$domain" 2>/dev/null | grep -q .; then
echo "$domain" # HAS MX -> stdout
else
echo "$domain" >&2 # NO MX -> stderr
fi
}
export -f check_domain
export dns_server
# Run in parallel
printf "%s\n" "$input" | \
xargs -P "$parallelism" -n 1 bash -c 'check_domain "$0" "$dns_server"'
# end