Of course! The dns.resolver module is a powerful and popular part of the dnspython library, which is the de-facto standard for DNS operations in Python. It allows you to programmatically perform DNS queries, just like a command-line tool like dig or nslookup.

Here’s a comprehensive guide covering everything from installation to advanced usage.
Installation
First, you need to install the dnspython library. You can do this easily using pip:
pip install dnspython
Basic Usage: Resolving a DNS Record
The most common task is to resolve a domain name to an IP address (an A record). The process involves creating a Resolver object, querying it, and then iterating through the results.
Here's a simple example to get the A records for google.com:

import dns.resolver
def resolve_domain(domain):
"""
Resolves a domain name to its A records (IPv4 addresses).
"""
try:
# Create a resolver object
resolver = dns.resolver.Resolver()
# Set a custom nameserver (optional, defaults to system's)
# resolver.nameservers = ['8.8.8.8', '1.1.1.1']
# Query for A records
answers = resolver.resolve(domain, 'A')
print(f"--- A records for {domain} ---")
for rdata in answers:
# rdata is a dns.rdatatype.A object
# The address is stored in the 'address' attribute
print(f"IP Address: {rdata.address}")
except dns.resolver.NXDOMAIN:
print(f"Error: The domain {domain} does not exist.")
except dns.resolver.NoAnswer:
print(f"Error: The domain {domain} does not have an A record.")
except dns.resolver.Timeout:
print(f"Error: No response from the DNS server for {domain}.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
# --- Example Usage ---
resolve_domain('google.com')
resolve_domain('this-domain-does-not-exist-12345.com') # Will trigger NXDOMAIN
Output:
--- A records for google.com ---
IP Address: 142.250.217.78
IP Address: 142.250.217.101
IP Address: 142.250.217.139
IP Address: 142.250.217.113
IP Address: 142.250.217.125
IP Address: 142.250.217.147
...
Handling Different Record Types
The dns.resolver.resolve() function is versatile. You can query for any valid DNS record type by changing the second argument.
Here are examples for common record types:
MX (Mail Exchange) Records
Shows mail servers responsible for receiving email on a domain.

import dns.resolver
try:
answers = dns.resolver.resolve('google.com', 'MX')
print(f"--- MX records for google.com ---")
for rdata in answers:
# rdata is a dns.rdatatype.MX object
# It has 'preference' and 'exchange' attributes
print(f" Priority: {rdata.preference}, Mail Server: {rdata.exchange}")
except Exception as e:
print(f"An error occurred: {e}")
Output:
--- MX records for google.com ---
Priority: 10, Mail Server: aspmx.l.google.com
Priority: 30, Mail Server: alt1.aspmx.l.google.com
Priority: 20, Mail Server: alt2.aspmx.l.google.com
Priority: 40, Mail Server: alt3.aspmx.l.google.com
Priority: 5, Mail Server: alt4.aspmx.l.google.com
CNAME (Canonical Name) Records
Shows an alias for another domain name.
import dns.resolver
try:
answers = dns.resolver.resolve('www.google.com', 'CNAME')
print(f"--- CNAME records for www.google.com ---")
for rdata in answers:
# rdata is a dns.rdatatype.CNAME object
# The target is stored in the 'target' attribute
print(f"Alias for: {rdata.target}")
except Exception as e:
print(f"An error occurred: {e}")
Output:
--- CNAME records for www.google.com ---
Alias for: www.google.com.
TXT (Text) Records
Stores arbitrary text strings, often used for SPF, DKIM, or verification.
import dns.resolver
try:
answers = dns.resolver.resolve('google.com', 'TXT')
print(f"--- TXT records for google.com ---")
for rdata in answers:
# rdata.strings is a list of bytes objects
for txt_string in rdata.strings:
print(f" Text: {txt_string.decode('utf-8')}")
except Exception as e:
print(f"An error occurred: {e}")
Output:
--- TXT records for google.com ---
Text: v=spf1 include:_netblocks.google.com include:_netblocks2.google.com include:_netblocks3.google.com ~all
Text: apple-site-verification=.....................
Text: google-site-verification=.....................
...
NS (Name Server) Records
Shows the authoritative name servers for a domain.
import dns.resolver
try:
answers = dns.resolver.resolve('google.com', 'NS')
print(f"--- NS records for google.com ---")
for rdata in answers:
# rdata is a dns.rdatatype.NS object
print(f" Name Server: {rdata.target}")
except Exception as e:
print(f"An error occurred: {e}")
Output:
--- NS records for google.com ---
Name Server: ns3.google.com.
Name Server: ns4.google.com.
Name Server: ns1.google.com.
Name Server: ns2.google.com.
Advanced Features
Changing Nameservers
By default, dnspython uses the nameservers listed in your system's /etc/resolv.conf (on Linux/macOS) or the Windows network settings. You can override this to use specific servers, like Google's Public DNS or Cloudflare's DNS.
import dns.resolver
# Use Google's Public DNS
resolver = dns.resolver.Resolver()
resolver.nameservers = ['8.8.8.8', '8.8.4.4']
try:
answers = resolver.resolve('google.com', 'A')
print(f"Resolved via Google's DNS:")
for rdata in answers:
print(f" {rdata.address}")
except Exception as e:
print(f"An error occurred: {e}")
Handling Timeouts and Retries
DNS queries can sometimes be slow or fail. You can configure the resolver to wait longer for a response and to retry a certain number of times.
import dns.resolver
resolver = dns.resolver.Resolver()
# Set timeout to 5 seconds (default is 3)
resolver.timeout = 5
# Set number of retries to 2 (default is 3)
resolver.retry_servfail = 2
try:
answers = resolver.resolve('google.com', 'A')
# ... process answers ...
except dns.resolver.Timeout:
print("The query timed out.")
except Exception as e:
print(f"An error occurred: {e}")
Reverse DNS Lookup (PTR Record)
A reverse lookup maps an IP address to a domain name.
import dns.resolver
def reverse_lookup(ip_address):
try:
# Use the resolve method with 'PTR' and the IP address
# The IP address must be converted to a special format
# e.g., 8.8.8.8 becomes 8.8.8.8.in-addr.arpa.
answers = dns.resolver.resolve_address(ip_address)
print(f"--- Reverse DNS for {ip_address} ---")
for rdata in answers:
# rdata is a dns.rdatatype.PTR object
print(f" Domain Name: {rdata.target}")
except Exception as e:
print(f"An error occurred: {e}")
reverse_lookup('8.8.8.8')
Output:
--- Reverse DNS for 8.8.8.8 ---
Domain Name: dns.google.
Common Exceptions
Handling exceptions is crucial for writing robust DNS clients.
dns.resolver.NXDOMAIN: The domain name does not exist.dns.resolver.NoAnswer: The name server does not have an answer for the query (e.g., an MX record for a domain that only has A records).dns.resolver.Timeout: No name server responded within the configured timeout.dns.resolver.NoNameservers: No non-broken nameservers are available to answer the query. This can indicate a network connectivity issue.dns.exception.DNSException: The base class for alldnspythonexceptions. You can catch this to handle any DNS-related error.
