Skip to content

Instantly share code, notes, and snippets.

@ashleykleynhans
Forked from dlage/README.md
Last active March 2, 2026 17:49
Show Gist options
  • Select an option

  • Save ashleykleynhans/69e4fb525d4f32d766313d3f9d22b688 to your computer and use it in GitHub Desktop.

Select an option

Save ashleykleynhans/69e4fb525d4f32d766313d3f9d22b688 to your computer and use it in GitHub Desktop.
Namecheap DNS to zone file
#!/usr/bin/env python3
#######################################################################################################################
# Generate DNS Zone file from Namecheap
#
# Modification History:
# Date Version Modified by Github URL Description
# 2016-03-11 1.0 Judotens Budiarto https://github.com/judotens Initial creation
# 2020-01-17 1.1 Andrew https://github.com/andrew-nuwber Resolve CAPTCHA issue
# 2020-12-07 1.2 Dinis https://github.com/dlage Cloudflare and AAAA record support
# 2022-08-30 1.3 Ashley Kleynhans https://github.com/ashleykleynhans Python3 and more DNS records support,
# Refactored code to break out of loop
# sooner, use argparse to validate
# command line arguments, option to
# choose default or cloudflare format.
# improved error handling, autodetect
# domain name.
#######################################################################################################################
"""
1. Login to Namecheap Account
2. Get JSON from https://ap.www.namecheap.com/Domains/dns/GetAdvancedDnsInfo?fillTransferInfo=false&domainName=YOURDOMAINNAME.com
3. Save it to file
4. `python get_namecheap_dns_records.py data.json`
"""
import argparse
import json
RECORD_TYPES = {
1: 'A',
2: 'CNAME',
3: 'MX',
5: 'TXT',
8: 'AAAA',
9: 'NS',
10: 'URL Redirect',
11: 'SRV',
12: 'CAA',
13: 'ALIAS'
}
def get_args():
parser = argparse.ArgumentParser(
description='Get Namecheap DNS records.',
)
parser.add_argument(
'filename',
type=str,
help='Filename'
)
parser.add_argument(
'--format', '-format', '--f', '-f',
type=str,
required=False,
default='default',
choices={'default', 'cloudflare'},
help='Output format (default/cloudflare)'
)
return parser.parse_args()
def parse_dns_info(dns_info, output_format):
items = []
if 'Result' in dns_info and\
'CustomHostRecords' in dns_info['Result'] and\
'Records' in dns_info['Result']['CustomHostRecords']:
records = dns_info['Result']['CustomHostRecords']['Records']
else:
raise KeyError('JSON is in an unexpected format')
if not len(records):
raise Exception('No DNS records found in JSON')
for record in records:
# Skip inactive records
if not record['IsActive']:
continue
# Skip unknown record types
if record['RecordType'] not in RECORD_TYPES.keys():
continue
record_type = RECORD_TYPES[record['RecordType']]
value = record['Data']
host = record['Host']
if record_type == 'MX':
value = f"{record['Priority']} {value}"
elif record_type == 'TXT':
value = f'"{value}"'
if output_format == 'cloudflare':
domain = dns_info['Result']['DomainBasicDetails']['DomainName']
if host == '@':
host = domain
else:
host = f'{host}.{domain}.'
items.append([
host,
str(record['Ttl']),
'IN',
record_type,
value
])
return items
if __name__ == '__main__':
try:
args = get_args()
filename = args.filename
output_format = args.format
file = open(filename, 'r')
dns_info = json.loads(file.read())
file.close()
records = parse_dns_info(dns_info, output_format)
for record in records:
print('\t'.join(record))
except (IOError, KeyError, Exception) as e:
print(f'ERROR: {e}')
except json.decoder.JSONDecodeError as e:
print(f'ERROR: Unable to decode JSON from {filename}: {e}')
@That-Dude
Copy link

Thank you very much for this, it's ridiculous that NC don't have this built in.

@isokosan
Copy link

Works like a charm, I spent more time trying to talk to 3 namecheap representatives, should've come directly here!

@lwwarner
Copy link

lwwarner commented Apr 22, 2025

Getting a syntax error at line 91:

  File "../get_namecheap_dns_records.py", line 91
    value = f"{record['Priority']} {value}"
                                          ^
SyntaxError: invalid syntax

@ashleykleynhans
Copy link
Author

File "../get_namecheap_dns_records.py", line 91
value = f"{record['Priority']} {value}"
^
SyntaxError: invalid syntax

What version of Python are you using? This looks like it may be a Python 2 issue. The script only supports Python 3 and not Python 2.

@zorbathut
Copy link

thank you for saving me from manually transcribing several dozen DNS entries

@belgareth
Copy link

Thanks been helpful aF

@ephraimduncan
Copy link

Made some small modifications, added $ORIGIN directive, $TTL, and SOA record to zone file output, and writes to {domain}-zone.txt instead of stdout.

# main.py

"""
1. Login to Namecheap Account
2. Get JSON from https://ap.www.namecheap.com/Domains/dns/GetAdvancedDnsInfo?fillTransferInfo=false&domainName=YOURDOMAINNAME.com
3. Save it to file
4. `python get_namecheap_dns_records.py data.json`
"""
import argparse
import json

RECORD_TYPES = {
    1: 'A',
    2: 'CNAME',
    3: 'MX',
    5: 'TXT',
    8: 'AAAA',
    9: 'NS',
    10: 'URL Redirect',
    11: 'SRV',
    12: 'CAA',
    13: 'ALIAS'
}


def get_args():
    parser = argparse.ArgumentParser(
        description='Get Namecheap DNS records.',
    )

    parser.add_argument(
        'filename',
        type=str,
        help='Filename'
    )

    parser.add_argument(
        '--format', '-format', '--f', '-f',
        type=str,
        required=False,
        default='default',
        choices={'default', 'cloudflare'},
        help='Output format (default/cloudflare)'
    )

    return parser.parse_args()


def get_domain(dns_info):
    return dns_info['Result']['DomainBasicDetails']['DomainName']


def zone_header(domain):
    from datetime import date
    serial = date.today().strftime('%Y%m%d') + '01'
    return (
        f'$ORIGIN {domain}.\n'
        f'$TTL 1799\n'
        f'@  IN  SOA  ns1.registrar-servers.com.  admin.{domain}. (\n'
        f'    {serial}  ; serial\n'
        f'    3600        ; refresh\n'
        f'    600         ; retry\n'
        f'    604800      ; expire\n'
        f'    1799        ; minimum\n'
        f')'
    )


def parse_dns_info(dns_info, output_format):
    items = []

    if 'Result' in dns_info and\
    'CustomHostRecords' in dns_info['Result'] and\
    'Records' in dns_info['Result']['CustomHostRecords']:
        records = dns_info['Result']['CustomHostRecords']['Records']
    else:
        raise KeyError('JSON is in an unexpected format')

    if not len(records):
        raise Exception('No DNS records found in JSON')

    for record in records:
        # Skip inactive records
        if not record['IsActive']:
            continue

        # Skip unknown record types
        if record['RecordType'] not in RECORD_TYPES.keys():
            continue

        record_type = RECORD_TYPES[record['RecordType']]
        value = record['Data']
        host = record['Host']

        if record_type == 'MX':
            value = f"{record['Priority']} {value}"
        elif record_type == 'TXT':
            value = f'"{value}"'

        if output_format == 'cloudflare':
            domain = dns_info['Result']['DomainBasicDetails']['DomainName']
            if host == '@':
                host = domain
            else:
                host = f'{host}.{domain}.'

        items.append([
            host,
            str(record['Ttl']),
            'IN',
            record_type,
            value
        ])

    return items


if __name__ == '__main__':
    try:
        args = get_args()
        filename = args.filename
        output_format = args.format
        file = open(filename, 'r')
        dns_info = json.loads(file.read())
        file.close()
        domain = get_domain(dns_info)
        records = parse_dns_info(dns_info, output_format)

        lines = [zone_header(domain)]
        for record in records:
            lines.append('\t'.join(record))

        output = '\n'.join(lines) + '\n'
        output_file = f'{domain}-zone.txt'
        with open(output_file, 'w') as f:
            f.write(output)
        print(f'Wrote {output_file}')
    except (IOError, KeyError, Exception) as e:
        print(f'ERROR: {e}')
    except json.decoder.JSONDecodeError as e:
        print(f'ERROR: Unable to decode JSON from {filename}: {e}')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment