- Aug 18, 2026
- 5 min read
Mailjet Held My Emails: Validating a Sending Subdomain with Cloudflare DNS
I moved my confirmation emails to Mailjet on a dedicated sending subdomain,
news.jalcocertech.com. SPF included Mailjet, the DKIM key was published,
the API accepted every request with "Status": "success" — and nothing
arrived. A few minutes later this landed in my inbox instead:
A non-validated sender address was used on your account. You tried to send an email with sender address [email protected], but this sender address has not been validated yet. Please validate the sender within 3 days, so that we can send your email.
So the API said “success” and the provider quietly held the messages. Here is what was missing and the DNS trap that made it take longer than it should.
Three different records, three different jobs
I had assumed SPF + DKIM = “domain set up”. Mailjet wants three things, and they answer different questions:
| Record | Where | Question it answers |
|---|---|---|
SPF v=spf1 include:spf.mailjet.com ~all | news.jalcocertech.com | May Mailjet’s servers send for this domain? |
DKIM mailjet._domainkey | mailjet._domainkey.news.jalcocertech.com | Is this message really signed by this domain? |
Ownership mailjet._<code> = <code> | mailjet._<code>.news.jalcocertech.com | Does this Mailjet account control the domain? |
The first two are about receivers trusting the mail. The third is about
Mailjet trusting me: until it resolves, any sender address on the domain is
“non-validated” and messages wait in a queue. That is why the API answered
success — the message was accepted, just not released.
The trap: Cloudflare appends the zone
Mailjet’s domain page gives the ownership record as a host name like
mailjet._1a2b3c4d.news.jalcocertech.com with the value 1a2b3c4d….
In Cloudflare’s DNS editor the zone is jalcocertech.com, and whatever you
type in Name gets .jalcocertech.com appended.
I typed mailjet._1a2b3c4d. Cloudflare saved
mailjet._1a2b3c4d.jalcocertech.com — the apex, not the subdomain Mailjet
was checking. The record existed, looked right in the list, and was useless.
| Typed in Name | Resulting record | Mailjet sees it? |
|---|---|---|
mailjet._1a2b3c4d | mailjet._1a2b3c4d.jalcocertech.com | No |
mailjet._1a2b3c4d.news | mailjet._1a2b3c4d.news.jalcocertech.com | Yes |
The fix was an edit, not a new record: rename it to mailjet._1a2b3c4d.news,
same value. A minute later Mailjet showed the domain as validated.
It’s the same family of mistake as a leading space pasted into a redirect rule (apex vs www and pages.dev redirects): the dashboard accepts it, the result is subtly wrong, and only checking the real answer from DNS shows it.
Checking with dig
Before pressing “Validate”, I check that the name actually answers:
dig +short TXT mailjet._1a2b3c4d.news.jalcocertech.com
dig +short TXT mailjet._1a2b3c4d.jalcocertech.com # where it shouldn't be
One gotcha: right after the rename, my local resolver returned an empty answer for the new name. It had cached the earlier “doesn’t exist” response. Asking a public resolver directly showed the truth:
dig +short TXT mailjet._1a2b3c4d.news.jalcocertech.com @1.1.1.1
"1a2b3c4d…"
So: an empty answer right after a change can be your own resolver’s negative
cache. Query @1.1.1.1 (or @8.8.8.8) before concluding the record is wrong.
Validate the domain, not the address
Mailjet also offers validating a single sender address: it emails that address
a link. My sender is [email protected], and the subdomain has no
MX record — nothing can receive mail there. I could have set up Cloudflare
Email Routing to forward noreply@ somewhere, but that’s extra moving parts
for no gain.
Domain validation by DNS covers every address on the subdomain
(noreply@, hello@, whatever comes later) and needs no inbox. For a
send-only subdomain it’s the only sensible choice.
What happened to the held emails
The good news: nothing was lost. Mailjet’s message said it would hold the
email for three days. Once the domain validated, the held confirmation email
was released and delivered — I clicked it and the subscription moved from
pending to confirmed in my lead store.
Still, “held” looks exactly like “lost” from the sending side. The Worker had logged success; the only signals were Mailjet’s email to the account owner and the message history in Mailjet’s dashboard. I’ve added “check the provider’s message history” to my go-live checklist, next to checking the API response.
DMARC and alignment on a subdomain
I didn’t add a DMARC record on news.. The root domain has one:
_dmarc.jalcocertech.com "v=DMARC1; p=quarantine"
Without an sp= tag, the root’s policy applies to subdomains too, so mail
from news.jalcocertech.com is judged under p=quarantine. That’s fine
because DKIM is aligned: the From domain is news.jalcocertech.com and
Mailjet signs with the mailjet._domainkey.news.jalcocertech.com key, so
d= matches the From domain. SPF is set on the same subdomain as well.
The root domain’s own mail stays untouched: its MX and SPF point at my regular mailbox provider, and manual mail keeps going out from there. The subdomain exists so automated mail has its own reputation and its own records.
Other providers can share the subdomain
The same subdomain also carries records from another provider I tried
earlier (Resend: a resend._domainkey key and its own send. / rsend.
names). They don’t conflict: DKIM selectors have different names, and each
provider’s validation lives under its own label. Only SPF is shared — one
TXT record per name — so if two providers send from the exact same domain,
both include:s go into that one record. Unused providers’ records are worth
removing later just to keep the zone readable.
The checklist I use now
- Add the sending subdomain in the provider’s dashboard.
- Create all the records it lists — SPF, DKIM, and ownership.
- In Cloudflare, type names relative to the zone:
mailjet._<code>.news, notmailjet._<code>. dig +short TXT <full name> @1.1.1.1for each one.- Press validate; send one test through the provider’s API.
- Look at the provider’s message history, not only the API response.
Takeaways
- SPF and DKIM make receivers trust your mail; ownership validation makes the provider release it. You need both.
- Cloudflare appends the zone to whatever you type. For subdomain records, include the subdomain label in the name.
- An empty
digright after a change may be a cached negative answer — ask a public resolver. - Validate the whole sending domain by DNS; a
noreply@address can’t click a validation link. - “Accepted by the API” is not “delivered”. Held mail looks like success until you check the provider’s side.
Next: one sender adapter, two providers — switching Mailtrap and Mailjet without code changes.