<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Thanh Ho Van</title>
    <description>The latest articles on DEV Community by Thanh Ho Van (@thanh_hovan_29d27c74b1e0).</description>
    <link>https://dev.to/thanh_hovan_29d27c74b1e0</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4116976%2F07a0ae91-d73e-4e85-b121-3279ab0fd97b.png</url>
      <title>DEV Community: Thanh Ho Van</title>
      <link>https://dev.to/thanh_hovan_29d27c74b1e0</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thanh_hovan_29d27c74b1e0"/>
    <language>en</language>
    <item>
      <title>How to Set Up Custom-Domain Email with SPF, DKIM, and DMARC</title>
      <dc:creator>Thanh Ho Van</dc:creator>
      <pubDate>Thu, 10 Sep 2026 08:16:47 +0000</pubDate>
      <link>https://dev.to/thanh_hovan_29d27c74b1e0/how-to-set-up-custom-domain-email-with-spf-dkim-and-dmarc-1pf8</link>
      <guid>https://dev.to/thanh_hovan_29d27c74b1e0/how-to-set-up-custom-domain-email-with-spf-dkim-and-dmarc-1pf8</guid>
      <description>&lt;p&gt;Setting up email on a domain you own is mostly a DNS task. The confusing part is that several records solve different problems: receiving mail, proving domain ownership, authorizing senders, signing messages, and publishing an anti-spoofing policy.&lt;/p&gt;

&lt;p&gt;This guide explains the five record groups used by &lt;strong&gt;Free Domain Mail&lt;/strong&gt;, a lightweight browser-based mailbox service for freelancers, developers, solo founders, personal projects, and small teams with low email volume.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/1EQELQDziyw" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What you need before starting
&lt;/h2&gt;

&lt;p&gt;You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A domain that you own&lt;/li&gt;
&lt;li&gt;Access to its authoritative DNS provider&lt;/li&gt;
&lt;li&gt;A Free Domain Mail account&lt;/li&gt;
&lt;li&gt;A few minutes for DNS caches to refresh&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You do not need to transfer your domain or operate your own mail server.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Verify domain ownership with TXT
&lt;/h2&gt;

&lt;p&gt;The first TXT record proves that you control the domain. Its value is generated specifically for your setup.&lt;/p&gt;

&lt;p&gt;Add the exact host and value shown in the setup screen. Do not remove unrelated TXT records already used for site verification or other services.&lt;/p&gt;

&lt;p&gt;After publishing the record, run the verification check again. DNS propagation may be fast, but some providers and resolvers cache results longer.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Route incoming email with MX
&lt;/h2&gt;

&lt;p&gt;An MX record tells other mail systems where messages for your domain should be delivered.&lt;/p&gt;

&lt;p&gt;Before changing MX, review any existing records. Replacing the current MX records will change where new mail is delivered. If the domain already uses another email provider, plan the migration instead of editing records blindly.&lt;/p&gt;

&lt;p&gt;The priority number matters when multiple MX records exist: a lower number normally has higher priority.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Authorize sending with SPF
&lt;/h2&gt;

&lt;p&gt;SPF is a TXT policy that lists the services allowed to send mail for the domain.&lt;/p&gt;

&lt;p&gt;A domain should normally publish &lt;strong&gt;one SPF record&lt;/strong&gt;. If one already exists, merge the required authorization into the existing policy. Publishing two independent records beginning with v=spf1 can cause SPF evaluation errors.&lt;/p&gt;

&lt;p&gt;SPF helps receiving systems detect unauthorized infrastructure, but it does not cryptographically sign the message.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Authenticate messages with DKIM
&lt;/h2&gt;

&lt;p&gt;DKIM adds a cryptographic signature to outgoing messages. Receiving systems use DNS to obtain the public key and verify that the signed parts of the message were not altered.&lt;/p&gt;

&lt;p&gt;Free Domain Mail displays the required DKIM CNAME records during setup. Copy each hostname and target exactly. Some DNS dashboards automatically append the domain name, so check the final public record if verification fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Publish a DMARC policy
&lt;/h2&gt;

&lt;p&gt;DMARC connects SPF and DKIM results to the domain visible in the From address. It also tells receivers what to do when authentication fails.&lt;/p&gt;

&lt;p&gt;A cautious starting policy is often:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=DMARC1; p=none; rua=mailto:dmarc@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Replace the reporting address with a mailbox you control. A monitoring policy does not directly reject mail. Move toward quarantine or reject only after reviewing legitimate sending sources and alignment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify the public result
&lt;/h2&gt;

&lt;p&gt;After saving all records, check what the public DNS actually returns—not only what the provider dashboard displays.&lt;/p&gt;

&lt;p&gt;The free &lt;a href="https://freedomainmail.com/tools/dns-checker" rel="noopener noreferrer"&gt;DNS Checker&lt;/a&gt; inspects MX, SPF, DMARC, A, AAAA, and nameserver records. You can also follow the complete &lt;a href="https://freedomainmail.com/guide" rel="noopener noreferrer"&gt;five-step setup guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Common causes of failed verification include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checking before caches have refreshed&lt;/li&gt;
&lt;li&gt;Adding the full domain twice in the hostname field&lt;/li&gt;
&lt;li&gt;Publishing multiple SPF records&lt;/li&gt;
&lt;li&gt;Leaving an old MX record active&lt;/li&gt;
&lt;li&gt;Copying whitespace or punctuation incorrectly&lt;/li&gt;
&lt;li&gt;Editing DNS at a provider that is not authoritative for the domain&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Free Domain Mail currently provides
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://freedomainmail.com/" rel="noopener noreferrer"&gt;Free Domain Mail&lt;/a&gt; is currently a free beta with a simple webmail interface. It stores received and sent messages and supports reading, composing, replying, manual forwarding, archiving, spam marking, and deletion.&lt;/p&gt;

&lt;p&gt;Current free limits include up to three mailboxes per domain, five sent messages per domain per day, and ten received messages per domain per day. No credit card is required.&lt;/p&gt;

&lt;p&gt;It is designed for low-volume personal and small-business use. It does &lt;strong&gt;not currently provide IMAP, SMTP/POP3 client access, aliases, catch-all addresses, shared mailboxes, automatic forwarding, mobile apps, attachments, or bulk sending&lt;/strong&gt;. Sending availability is also subject to Amazon SES service restrictions.&lt;/p&gt;

&lt;p&gt;These limits are intentional: the product focuses on guided DNS setup, a minimal browser inbox, and strong anti-abuse controls—not marketing campaigns or cold outreach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final checklist
&lt;/h2&gt;

&lt;p&gt;Before creating your first mailbox, confirm that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Domain ownership TXT passes&lt;/li&gt;
&lt;li&gt;MX points to the intended inbound service&lt;/li&gt;
&lt;li&gt;Only one valid SPF policy is published&lt;/li&gt;
&lt;li&gt;Every DKIM CNAME resolves correctly&lt;/li&gt;
&lt;li&gt;DMARC exists at _dmarc.yourdomain.com&lt;/li&gt;
&lt;li&gt;Existing website A, AAAA, and CNAME records remain unchanged&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once all five record groups pass, the domain is ready for a custom-domain web mailbox.&lt;/p&gt;

&lt;p&gt;Have you encountered a DNS-provider-specific issue while configuring email authentication? Share the provider and the symptom in the comments—without posting private tokens or account credentials.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>dns</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How to Set Up SPF, DKIM and DMARC for a Custom Domain</title>
      <dc:creator>Thanh Ho Van</dc:creator>
      <pubDate>Wed, 09 Sep 2026 07:03:32 +0000</pubDate>
      <link>https://dev.to/thanh_hovan_29d27c74b1e0/how-to-set-up-spf-dkim-and-dmarc-for-a-custom-domain-367i</link>
      <guid>https://dev.to/thanh_hovan_29d27c74b1e0/how-to-set-up-spf-dkim-and-dmarc-for-a-custom-domain-367i</guid>
      <description>&lt;p&gt;Email authentication can look like a collection of unrelated DNS records. In practice, each record answers a different question:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SPF:&lt;/strong&gt; Which servers may send mail for this domain?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DKIM:&lt;/strong&gt; Was this message signed by an authorized sender, and did it change in transit?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DMARC:&lt;/strong&gt; Does the visible From domain align with SPF or DKIM, and what should receivers do when authentication fails?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide shows a safe, provider-neutral setup sequence for a custom domain.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The DNS values below are examples. Always copy the actual hostnames, selectors, and targets supplied by your email provider.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Before changing DNS
&lt;/h2&gt;

&lt;p&gt;Confirm three things first:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You control the domain's authoritative DNS zone.&lt;/li&gt;
&lt;li&gt;You know every service that currently sends mail for the domain.&lt;/li&gt;
&lt;li&gt;You have saved a copy of the existing MX and TXT records.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not delete website A, AAAA, or CNAME records while configuring email. Email DNS and website DNS normally coexist.&lt;/p&gt;

&lt;p&gt;You can inspect the records currently visible on the public internet with the &lt;a href="https://freedomainmail.com/tools/dns-checker" rel="noopener noreferrer"&gt;Free Domain Mail DNS Checker&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Configure MX for incoming mail
&lt;/h2&gt;

&lt;p&gt;MX records tell other mail systems where to deliver messages addressed to your domain.&lt;/p&gt;

&lt;p&gt;A simplified example looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Type: MX
Name: @
Priority: 10
Value: inbound.mail-provider.example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;@&lt;/code&gt; symbol usually means the root domain, but DNS dashboards differ. Some expect a blank name, while others expect the complete domain.&lt;/p&gt;

&lt;p&gt;Important rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the exact MX destination supplied by the receiving provider.&lt;/li&gt;
&lt;li&gt;Lower priority numbers are tried first.&lt;/li&gt;
&lt;li&gt;Remove an old MX record only when you intentionally stop using the old receiver.&lt;/li&gt;
&lt;li&gt;Do not point MX to an ordinary website IP address.&lt;/li&gt;
&lt;li&gt;If you use Cloudflare, mail hostnames generally need to remain &lt;strong&gt;DNS only&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MX controls receiving. It does not authorize outgoing mail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Publish one SPF policy
&lt;/h2&gt;

&lt;p&gt;SPF is stored as a TXT record. It lists the infrastructure allowed to send using a particular envelope domain.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Type: TXT
Name: @
Value: v=spf1 include:spf.mail-provider.example -all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most common SPF mistake is publishing two records such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=spf1 include:service-a.example -all
v=spf1 include:service-b.example -all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That does not create two valid policies. It normally produces an SPF permanent error. Combine legitimate senders into a single record instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;v=spf1 include:service-a.example include:service-b.example -all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also remember:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SPF has a DNS-lookup limit.&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;include&lt;/code&gt; authorizes another provider's policy; it is not a redirect.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~all&lt;/code&gt; is a soft-fail qualifier and &lt;code&gt;-all&lt;/code&gt; is a hard-fail qualifier.&lt;/li&gt;
&lt;li&gt;Changing to &lt;code&gt;-all&lt;/code&gt; before identifying every sender may break legitimate mail.&lt;/li&gt;
&lt;li&gt;SPF alone may not satisfy DMARC when the authenticated envelope domain does not align with the visible From domain.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Enable DKIM signing
&lt;/h2&gt;

&lt;p&gt;DKIM adds a cryptographic signature to outgoing messages. The sending service holds the private key, while DNS publishes the public key or a CNAME pointing to it.&lt;/p&gt;

&lt;p&gt;A provider may give you records like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Type: CNAME
Name: selector1._domainkey
Value: selector1.dkim.mail-provider.example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some services provide one selector; others provide several. Publish every record shown in the provider dashboard.&lt;/p&gt;

&lt;p&gt;Common DKIM problems include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Entering the whole hostname when the DNS dashboard automatically appends the domain.&lt;/li&gt;
&lt;li&gt;Checking &lt;code&gt;default._domainkey&lt;/code&gt; when the provider uses another selector.&lt;/li&gt;
&lt;li&gt;Creating a TXT record when the provider requested a CNAME.&lt;/li&gt;
&lt;li&gt;Copying a target with missing characters.&lt;/li&gt;
&lt;li&gt;Assuming that a published key means the sender has started signing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After DNS verification, send a real test message and inspect its headers. Look for &lt;code&gt;dkim=pass&lt;/code&gt; and verify that the signing domain aligns with the From domain.&lt;/p&gt;

&lt;p&gt;For a more detailed walkthrough, see this &lt;a href="https://freedomainmail.com/guides/dkim" rel="noopener noreferrer"&gt;DKIM setup guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Start DMARC in monitoring mode
&lt;/h2&gt;

&lt;p&gt;DMARC is a TXT record at &lt;code&gt;_dmarc.yourdomain.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A sensible starting policy is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Type: TXT
Name: _dmarc
Value: v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;p=none&lt;/code&gt;, receivers can send aggregate reports without being asked to quarantine or reject failures. This gives you time to find forgotten senders and alignment problems.&lt;/p&gt;

&lt;p&gt;A safe rollout is usually:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Begin with &lt;code&gt;p=none&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Review reports and fix legitimate failures.&lt;/li&gt;
&lt;li&gt;Move a small percentage to &lt;code&gt;p=quarantine&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Increase enforcement gradually.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;p=reject&lt;/code&gt; only when authorized mail is consistently aligned.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The reporting address must be able to receive and process DMARC aggregate reports. These are XML files and can arrive in significant volume.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Verify alignment, not only individual passes
&lt;/h2&gt;

&lt;p&gt;A message can show &lt;code&gt;spf=pass&lt;/code&gt; and still fail DMARC if SPF authenticated a different organizational domain. Likewise, DKIM must pass with an aligned signing domain.&lt;/p&gt;

&lt;p&gt;DMARC passes when at least one aligned mechanism passes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SPF passes &lt;strong&gt;and&lt;/strong&gt; the authenticated SPF domain aligns with the From domain, or&lt;/li&gt;
&lt;li&gt;DKIM passes &lt;strong&gt;and&lt;/strong&gt; the DKIM signing domain aligns with the From domain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This distinction matters with ticketing systems, newsletters, transactional platforms, and forwarding services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful DNS checks
&lt;/h2&gt;

&lt;p&gt;Replace the example domain and selector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dig +short MX example.com
dig +short TXT example.com
dig +short TXT _dmarc.example.com
dig +short CNAME selector1._domainkey.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If results differ between tools, query the authoritative nameserver directly. That helps distinguish a bad record from a resolver cache that has not refreshed yet.&lt;/p&gt;

&lt;p&gt;DNS changes can appear quickly or take longer depending on TTL values and resolver caches. Repeatedly saving the same record does not make propagation faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final validation checklist
&lt;/h2&gt;

&lt;p&gt;Before declaring the configuration complete:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] The intended MX destinations are publicly visible.&lt;/li&gt;
&lt;li&gt;[ ] There is exactly one SPF record at each sending hostname.&lt;/li&gt;
&lt;li&gt;[ ] Every legitimate sender is included in the SPF design.&lt;/li&gt;
&lt;li&gt;[ ] All provider-issued DKIM selectors resolve.&lt;/li&gt;
&lt;li&gt;[ ] Test messages show DKIM signatures.&lt;/li&gt;
&lt;li&gt;[ ] DMARC exists at &lt;code&gt;_dmarc&lt;/code&gt;, not at the root.&lt;/li&gt;
&lt;li&gt;[ ] SPF or DKIM passes with DMARC alignment.&lt;/li&gt;
&lt;li&gt;[ ] Bounce and complaint handling is active.&lt;/li&gt;
&lt;li&gt;[ ] DMARC reports are being reviewed.&lt;/li&gt;
&lt;li&gt;[ ] No API keys, SMTP passwords, or private keys were published.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A practical order of operations
&lt;/h2&gt;

&lt;p&gt;For a new domain, I prefer this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Verify ownership with the email provider.&lt;/li&gt;
&lt;li&gt;Publish DKIM.&lt;/li&gt;
&lt;li&gt;Configure SPF for known senders.&lt;/li&gt;
&lt;li&gt;Point MX to the receiving service.&lt;/li&gt;
&lt;li&gt;Add DMARC with &lt;code&gt;p=none&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Send and receive test messages.&lt;/li&gt;
&lt;li&gt;Review headers and reports.&lt;/li&gt;
&lt;li&gt;Tighten the DMARC policy gradually.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This order reduces the chance of enforcing a policy before authentication is actually working.&lt;/p&gt;

&lt;p&gt;If you want a concise version you can keep beside your DNS dashboard, the public &lt;a href="https://github.com/thanh743/email-dns-checklist" rel="noopener noreferrer"&gt;email DNS checklist on GitHub&lt;/a&gt; contains provider-neutral examples and an Amazon SES-specific companion guide.&lt;/p&gt;

&lt;p&gt;What DNS provider or email service are you configuring? Share the record types—not credentials—in the comments, and I can help identify the usual pitfalls.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>tutorial</category>
      <category>networking</category>
    </item>
  </channel>
</rss>
