Guides
Domains & DNS
Add a sending domain and publish its DKIM, return-path (MX + SPF) and DMARC records. How verification works and how to fix the usual DNS problems.
Pidgely sends only from domains you have verified. Verification proves you control the domain and, more importantly, sets up the authentication that mailbox providers check before they trust your mail: DKIM, an SPF-aligned return path and DMARC.
Add a domain
import { Pidgely } from 'pidgely';
const pidgely = new Pidgely(process.env.PIDGELY_API_KEY);
const { data, error } = await pidgely.domains.create({
name: 'acme.com',
});
console.log(data ?? error);import os
import pidgely
pidgely.api_key = os.environ["PIDGELY_API_KEY"]
result = pidgely.Domains.create({
"name": "acme.com",
})
print(result)<?php
require __DIR__ . '/vendor/autoload.php';
$pidgely = Pidgely::client(getenv('PIDGELY_API_KEY'));
$result = $pidgely->domains->create([
'name' => 'acme.com',
]);
var_dump($result);package main
import (
"context"
"fmt"
"os"
"github.com/pidgely/pidgely-go"
)
func main() {
ctx := context.Background()
client := pidgely.NewClient(os.Getenv("PIDGELY_API_KEY"))
result, err := client.Domains.Create(ctx, &pidgely.CreateDomainRequest{
Name: "acme.com",
})
if err != nil {
panic(err)
}
fmt.Println(result)
}require "pidgely"
Pidgely.api_key = ENV["PIDGELY_API_KEY"]
result = Pidgely::Domains.create({
name: "acme.com"
})
puts resultcurl -X POST 'https://api.pidgely.com/domains' \
-H "Authorization: Bearer $PIDGELY_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"name": "acme.com"
}'The response (Create a domain) includes the records to publish. Names are relative to your domain:
| Purpose | Type | Name | Value |
|---|---|---|---|
| DKIM | TXT |
pdg202610._domainkey |
v=DKIM1; k=rsa; p=MIIBIjANBg… (RSA-2048 public key) |
| Return path | MX |
bounces |
mta.pidgely.com, priority 10 |
| SPF | TXT |
bounces |
v=spf1 include:_spf.mta.pidgely.com ~all |
| DMARC (recommended) | TXT |
_dmarc |
v=DMARC1; p=none; |
Always copy the exact values from the API response or the dashboard: the DKIM selector (pdg plus the year and month the domain was added) and the key are unique to your domain.
Why these records
- DKIM signs every message with a key only Pidgely holds; receivers fetch the public key from
pdg…._domainkey.acme.com. Pidgely signs with relaxed/relaxed canonicalization and oversigns From, Subject and To. - Return path. Bounces go to
bounces.acme.com(the envelope sender, with a per-message VERP address). TheMXroutes bounces back to Pidgely so they are processed automatically, and the SPF record authorizes Pidgely's servers for that subdomain. Because it is a subdomain of yours, SPF aligns with your From domain for DMARC. - DMARC tells receivers what to do when authentication fails and where to send reports. Start with
p=none, watch the reports, then move toquarantineorreject. Pidgely does not require DMARC to send, but Gmail and Yahoo require it for bulk senders.
Read more in SPF, DKIM and DMARC explained.
Options
| Field | Description |
|---|---|
custom_return_path |
Label of the return-path subdomain, default bounces. One DNS label: lowercase letters, digits and hyphens (^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$). |
tls |
opportunistic (default): use TLS whenever the receiving server offers it. enforced: deliver only over TLS, otherwise retry and eventually fail. Change it later with Update a domain. |
region is informative, and open/click tracking and receiving are not supported yet: capabilities.receiving: "enabled" is rejected.
Verification
After publishing the records, call Verify a domain or wait: new domains are re-checked every 5 minutes during their first 3 days, and every domain is re-checked daily afterwards.
| Status | Meaning |
|---|---|
not_started |
The domain was added but never checked. |
pending |
Checked, but some required records are missing or wrong. DNS can take minutes (rarely hours) to propagate. |
verified |
DKIM, the return-path MX and SPF all pass. You can send. |
failed |
Records that used to pass no longer do (DNS changed), or the domain stayed unverified for more than 72 hours when verification was requested. Fix the DNS and verify again. |
Each record in records[] has its own status, so you can see exactly which one is missing. Status changes emit a domain.updated webhook.
Rules
- Exact match. Mail from
news.acme.comneedsnews.acme.comadded as its own domain;acme.comdoesn't cover subdomains. - One account per domain. A domain can be verified by only one Pidgely account. Verifying a domain already verified elsewhere fails with
… is verified by another account. - Plan limits. Free allows 1 domain, Starter 3, Growth 10, Scale unlimited (plans). Adding more returns
403 validation_error. - Deleting a domain stops sending from it immediately; messages still queued for it are retried and eventually fail.
Troubleshooting
The record exists but Pidgely says it's missing. Many DNS providers append your domain automatically. If you entered pdg202610._domainkey.acme.com as the name, the provider may have created pdg202610._domainkey.acme.com.acme.com. Enter only the relative part (pdg202610._domainkey).
Check what the world sees with dig (or nslookup -type=TXT):
dig +short TXT pdg202610._domainkey.acme.com
dig +short MX bounces.acme.com
dig +short TXT bounces.acme.com
dig +short TXT _dmarc.acme.comDKIM value split or truncated. A 2048-bit key is longer than 255 characters. Most providers split long TXT values automatically; if yours asks for it, paste the value as several quoted strings in one record ("v=DKIM1; k=rsa; p=MIIB…" "…rest"). Make sure no quotes or spaces were added inside the key.
MX on bounces conflicts with a CNAME. A name can't have both. Remove the CNAME or choose another label with custom_return_path.
Two SPF records on the same name. If bounces.acme.com already had an SPF record, merge them into one: a name can have only one v=spf1 record.
Cloudflare and other proxies. MX and TXT records are never proxied, so no special setting is needed.
Still stuck? Contact support with the domain name; we can see which check fails.