DEV Community

Alex Spinov
Alex Spinov

Posted on

DNS Over HTTPS Is Free — Here's How to Use It as an API (Python)

Most DNS tools are command-line only (dig, nslookup). But Cloudflare and Google offer DNS over HTTPS — you can query DNS from Python like any other API.

Cloudflare DNS API (No Key)

import requests

def dns_lookup(domain, record_type='A'):
    resp = requests.get('https://cloudflare-dns.com/dns-query', params={
        'name': domain, 'type': record_type
    }, headers={'Accept': 'application/dns-json'})
    return resp.json().get('Answer', [])

# A records
for r in dns_lookup('google.com', 'A'):
    print(f"  {r['name']}{r['data']} (TTL: {r['TTL']}s)")
Enter fullscreen mode Exit fullscreen mode

All Record Types

# MX records (email servers)
for r in dns_lookup('google.com', 'MX'):
    print(f"  Mail: {r['data']}")

# TXT records (SPF, DKIM, etc)
for r in dns_lookup('google.com', 'TXT'):
    print(f"  TXT: {r['data'][:80]}")

# NS records (nameservers)
for r in dns_lookup('google.com', 'NS'):
    print(f"  NS: {r['data']}")

# CNAME records
for r in dns_lookup('www.github.com', 'CNAME'):
    print(f"  CNAME: {r['data']}")
Enter fullscreen mode Exit fullscreen mode

Practical Uses

1. Verify Email Configuration

def check_email_config(domain):
    mx = dns_lookup(domain, 'MX')
    txt = dns_lookup(domain, 'TXT')

    print(f"\n📧 Email config for {domain}:")
    print(f"  MX records: {len(mx)}")
    for r in mx:
        print(f"    {r['data']}")

    spf = [r for r in txt if 'spf' in r.get('data', '').lower()]
    dmarc = dns_lookup(f'_dmarc.{domain}', 'TXT')

    print(f"  SPF: {'' if spf else ''}")
    print(f"  DMARC: {'' if dmarc else ''}")

check_email_config('google.com')
check_email_config('example.com')
Enter fullscreen mode Exit fullscreen mode

2. Find Subdomains via Certificate Transparency

def find_subdomains(domain):
    resp = requests.get(f'https://crt.sh/?q=%25.{domain}&output=json')
    subs = set()
    for cert in resp.json():
        for name in cert.get('name_value', '').split('\n'):
            if name.endswith(domain):
                subs.add(name)
    return sorted(subs)

subs = find_subdomains('github.com')
print(f"Found {len(subs)} subdomains")
for s in list(subs)[:10]:
    print(f"  {s}")
Enter fullscreen mode Exit fullscreen mode

3. Bulk DNS Check

def bulk_dns(domains):
    for domain in domains:
        records = dns_lookup(domain, 'A')
        ips = [r['data'] for r in records]
        print(f"{domain:>25}{', '.join(ips) or 'No A record'}")

bulk_dns(['google.com', 'github.com', 'cloudflare.com', 'example.com'])
Enter fullscreen mode Exit fullscreen mode

Google DNS API (Alternative)

def dns_google(domain, record_type='A'):
    resp = requests.get('https://dns.google/resolve', params={
        'name': domain, 'type': record_type
    })
    return resp.json().get('Answer', [])
Enter fullscreen mode Exit fullscreen mode

Same format, different provider. Good for redundancy.


I built a full toolkit: dns-lookup-toolkit

More free API toolkits: awesome-free-research-apis


Do you use DoH in production? What for?


More: Apify scrapers | GitHub

Top comments (0)