Bulk-Adding Google Workspace Domain Aliases Without Service-Account Keys
How to replace repetitive Google Workspace and DNS setup with a safe, CSV-driven Python workflow using OAuth, the Admin SDK, Site Verification API, and GoDaddy DNS API.

I am Nandan, And you probably know me as a "Software Engineer who "hacked" an Airline to retrieve his luggage".
I am a full-time Software Engineer, Tech Speaker, and mentor. I enjoy talking about Web Development, Machine Learning, Natural language Processing, Machine learning Accelerated Mobile Pages, Progressive Web Apps, Cybersecurity, Chatbots, etc.
My claim to fame was when I posted a series of tweets on Twitter about data privacy issues on an airline’s website and the tweet got viral for all the good reasons. The story was covered by all major media portals all around the world including BBC, Saudi Gazette, Times of India, Boing Boing, Lallantop etc. and I have been interviewed by some major radio channels and podcasts.
In my free time, I like to indulge myself in activities like Photography, Gardening, Snooker, or Boxing. I am a proud owner of many plants, I sometimes talk to them (mostly pep talks).
Managing one domain in Google Workspace is straightforward. Managing ten, twenty, or more domains across several brands is where the process starts to hurt.
For every domain, an administrator has to prove ownership, publish a DNS record, wait for propagation, return to Google Workspace, add the domain, configure mail routing, and verify the result. None of those steps is especially difficult. The problem is repetition — and repetition is where small mistakes become outages.
I recently needed a better workflow for attaching a collection of brand domains to one Google Workspace account. The domains used GoDaddy DNS, and the intended behavior was simple: every existing Workspace user should receive the same username on every brand domain.
That made the domains good candidates for Google Workspace user alias domains. It also made the process a good candidate for automation. The result is a CSV-driven Python CLI with three commands — plan, apply, verify — that connects the Google Workspace Admin SDK, the Site Verification API, and the GoDaddy DNS API, authenticates with OAuth instead of a service-account key, and treats every write as something to check for before doing. Code's open source at github.com/sirius93/google-workspace-domain-alias-provisioner, link at the bottom too.
The problem with doing it manually
The manual workflow usually looks like this:
Open the Google Admin console.
Add a domain alias.
Copy Google's verification token.
Open the DNS provider.
Create the TXT record.
Wait for DNS propagation.
Ask Google to verify the domain.
Configure MX records.
Repeat for the next domain. Do this once and it feels harmless. Do it twenty times and several risks appear:
A domain is skipped.
A TXT value is copied incorrectly.
The wrong parent domain is selected.
Existing MX records are replaced accidentally.
The spreadsheet and the real configuration drift apart.
Nobody has a reliable record of what succeeded. The goal was not merely to make the process faster. The goal was to make it repeatable, inspectable, and safe to rerun.
Domain alias or secondary domain?
Before automating anything, it is important to choose the correct Google Workspace domain model.
A user alias domain gives existing users and groups equivalent addresses on another domain. If brand.example is an alias of company.example, then:
alex@company.example -> alex@brand.example
sales@company.example -> sales@brand.example
Both addresses point to the existing account or group. Users continue signing in with their primary address, and there is no separate mailbox.
A secondary domain is different. It is intended for a separate collection of users whose primary accounts live on that domain. Secondary-domain users normally require their own Workspace licences.
The automation described here is specifically for user alias domains. That keeps the mapping predictable: one parent Workspace domain, many brand domains, and matching usernames across all of them.
Google documents the distinction and current domain limits in its multiple-domain guidance.
Turning the domain list into a source of truth
The first useful improvement is surprisingly mundane: put the desired state in a CSV file.
domain,type,parent_domain,dns_provider
brand-one.example,domain_alias,company.example,godaddy
brand-two.example,domain_alias,company.example,godaddy
brand-three.example,domain_alias,company.example,godaddy
This file becomes the input to every operation. It is easy to review, version, split into pilot batches, and compare with the actual environment.
The script validates that:
Every domain is unique.
Every row has a parent domain.
The requested type is
domain_alias.The DNS provider is supported. That validation catches boring mistakes before an API call turns them into an operational problem.
The automation flow
The workflow connects three APIs:
Google Site Verification API generates a DNS verification token and confirms ownership.
GoDaddy Domains API v3 reads the zone and creates missing TXT or MX records.
Google Workspace Admin SDK Directory API creates and inspects domain aliases. For each CSV row, the tool performs this sequence:
Check whether the domain is already verified.
Check whether the Workspace alias already exists.
Read the current GoDaddy DNS records.
Request a Google verification token when needed.
Add the token as an apex TXT record if it is missing.
Poll public DNS until the token is visible.
Ask Google to verify ownership.
Create the Workspace domain alias under the configured parent.
Optionally add Google MX when — and only when — the domain has no MX records. The read-before-write behavior is essential. A rerun should continue an incomplete job, not create duplicates.
Why the CLI has plan, apply, and verify
Infrastructure tools are much easier to trust when inspection and mutation are separate operations.
The CLI exposes three commands:
python workspace_domain_aliases.py plan domains.csv
python workspace_domain_aliases.py apply domains.csv
python workspace_domain_aliases.py verify domains.csv
plan
plan is read-only. It checks Google and GoDaddy, then prints a compact summary:
DOMAIN DNS VERIFIED WORKSPACE MX
brand-one.example ok no missing 0
brand-two.example ok yes missing 5
brand-three.example ok no present 1
This answers the questions that matter before a change: Can the tool access the DNS zone? Does Google already recognize the owner? Does the Workspace alias already exist? Is mail already configured?
apply
apply creates missing ownership records, verifies domains, and creates missing Workspace aliases.
python workspace_domain_aliases.py apply domains.csv
DNS propagation is asynchronous, so the tool polls for the verification TXT record. If the record does not become visible before the timeout, the run reports the domain as pending. Nothing needs to be rolled back: wait, then rerun the same command.
verify
verify reconciles the CSV with the live state, checking ownership, alias presence, parent-domain association, and whether the domain has at least one MX record. A non-zero exit code makes it usable in a shell script or a future CI workflow.
Authentication without service-account keys
My first instinct was to use a service account with domain-wide delegation. That is a common design for unattended Workspace administration, but the organization enforced this policy:
iam.managed.disableServiceAccountKeyCreation
That was not a problem to work around. It was a useful security boundary.
Long-lived service-account JSON keys are portable credentials. If one leaks into a repository, backup, support ticket, or developer machine, it can be abused until revoked. Google recommends avoiding service-account keys when a safer authentication method fits the workload.
For a locally operated administrative tool, interactive OAuth is a good match. The application uses an OAuth 2.0 Desktop app client and asks the administrator to authorize two scopes:
https://www.googleapis.com/auth/admin.directory.domain
https://www.googleapis.com/auth/siteverification
The Python flow is conceptually simple:
from google_auth_oauthlib.flow import InstalledAppFlow
scopes = [
"https://www.googleapis.com/auth/admin.directory.domain",
"https://www.googleapis.com/auth/siteverification",
]
flow = InstalledAppFlow.from_client_secrets_file(
"oauth-client.json",
scopes,
)
credentials = flow.run_local_server(port=0)
The first run opens a browser. The administrator signs in and approves access. The resulting refresh token is stored locally and reused on later runs.
That token must still be treated like a password. It should never be committed, pasted into an issue, or stored beside public example files.
Connecting to Google Workspace
Once OAuth credentials are available, the Python client can construct both Google services:
from googleapiclient.discovery import build
directory = build(
"admin",
"directory_v1",
credentials=credentials,
cache_discovery=False,
)
verification = build(
"siteVerification",
"v1",
credentials=credentials,
cache_discovery=False,
)
Creating a domain alias uses the Directory API:
directory.domainAliases().insert(
customer="my_customer",
body={
"domainAliasName": "brand.example",
"parentDomainName": "company.example",
},
).execute()
Before inserting, the tool lists existing aliases and compares the live parent domain with the CSV. If an alias already exists under a different parent, the script stops instead of guessing how to repair it.
Automating domain verification
Google ownership verification has two distinct operations: obtain a token and verify the resource.
The request describes an internet domain and asks for DNS verification:
result = verification.webResource().getToken(
body={
"site": {
"identifier": "brand.example",
"type": "INET_DOMAIN",
},
"verificationMethod": "DNS",
}
).execute()
token = result["token"]
The token is published as an apex TXT record. Once it is visible in public DNS, the tool asks Google to verify the resource:
verification.webResource().insert(
verificationMethod="DNS",
body={
"site": {
"identifier": "brand.example",
"type": "INET_DOMAIN",
}
},
).execute()
Keeping these steps separate makes DNS propagation explicit. A successful API response from the DNS provider does not mean every resolver can see the record immediately.
Adding records through GoDaddy safely
GoDaddy's v3 DNS API supports individual record creation:
POST /v3/domains/zones/{zone}/dns-records
A verification record looks like this:
{
"type": "TXT",
"name": "@",
"data": "google-site-verification=...",
"ttl": 600
}
The safe pattern is:
List existing records of the relevant type.
Normalize record names and values.
Create the record only when an exact match is absent.
Never replace the entire DNS zone. This matters because DNS APIs differ. Some "set records" methods replace every record with a matching name and type. Others can replace the whole zone. A provisioning tool should use the narrowest operation available.
GoDaddy also warns that record creation is not inherently idempotent: blindly replaying a failed POST can create duplicates. Reading the zone before each write significantly reduces that risk.
Why MX changes are opt-in
Verification TXT records are additive and relatively low-risk. MX records are different: they control where inbound email is delivered.
The tool therefore does not touch MX during the default apply operation. Mail configuration requires an explicit flag:
python workspace_domain_aliases.py apply domains.csv --add-google-mx
Even with the flag, the tool adds smtp.google.com only when the domain has zero MX records. If any MX record already exists, it prints a warning and leaves the configuration untouched.
That conservative decision handles several real-world cases: the domain already uses Google's older five-record MX configuration, the domain uses Google's newer single-record configuration, another mail provider is still active, or the domain has intentional routing or migration records.
Automation should not interpret "different from my preferred configuration" as "safe to overwrite."
SPF, DKIM, and DMARC are also intentionally outside the first version. Each requires knowledge of the organization's complete mail-sending environment. For example, adding a second SPF record can make SPF invalid rather than more secure.
Making reruns safe
Bulk administrative work rarely completes in one flawless pass. DNS might be slow, one domain might belong to another account, an API can rate-limit a request, or an administrator might pause the rollout.
The tool is designed so that rerunning apply is normal:
Existing TXT token: skip creation.
Already verified domain: skip verification.
Existing Workspace alias with correct parent: skip insertion.
Existing MX records: leave unchanged.
Pending DNS: retry later. This is the practical meaning of idempotency for the workflow. The entire run may involve APIs whose individual POST operations are not idempotent, but the program checks the current state before deciding whether a write is necessary.
A rollout strategy that minimizes surprises
For a real environment, I would use the following sequence:
Export or back up every DNS zone.
Put one non-critical domain in a pilot CSV.
Run
plan.Inspect any existing MX records.
Run
applywithout the MX flag.Confirm the alias in the Google Admin console.
Test receiving mail after the approved MX change.
Confirm outbound authentication separately.
Expand to small batches.
Run
verifyand keep the output with the change record. The pilot is not ceremony. It confirms that the OAuth project, administrator privileges, Workspace tenant, GoDaddy account, authoritative nameservers, and API behavior all match the assumptions in the code.
What I would add next
The first release solves one narrow problem well. Natural next steps include:
DNS-provider adapters for Cloudflare, Route 53, TransIP, and others
Secondary-domain support
JSON output for CI and audit systems
Unit tests with mocked API responses
Explicit DNS backup and rollback workflows
SPF, DKIM, and DMARC validation without automatic enforcement
A keyless workload-identity design for approved unattended execution Any future provider should preserve the same safety contract: read before write, create only what is missing, never replace a zone implicitly, and require explicit intent for destructive actions.
Lessons learned
Three ideas mattered more than the API calls themselves.
First, model the desired state before writing code. The CSV is small, but it turns an informal checklist into something reviewable and repeatable.
Second, treat security controls as design input. A blocked service-account key did not require disabling an organization policy. It led to an authentication flow better suited to a human-operated CLI.
Third, make dangerous behavior inconvenient. The tool can automate MX creation, but only through an explicit flag, and it refuses to modify existing mail routing. A little friction is valuable when a command can affect production email.
That's usually the sweet spot for internal automation. I've open sourced it — if you're wiring up your own multi-brand Workspace setup, the CLI and the client wrappers are there to fork.
Resources
Source code: github.com/sirius93/ggwdap — plan/apply/verify CLI, CSV schema, and the Google + GoDaddy client wrappers described above.
Google Workspace Admin SDK Directory API
Google Site Verification API
Google Directory API Python quickstart
Google Workspace multiple-domain guidance
GoDaddy DNS API guide
Google Cloud authentication guidance
This project is not affiliated with or endorsed by Google or GoDaddy. DNS and mail-routing changes can disrupt production services; test with a non-critical domain and keep current DNS backups.





