<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Txt on inetshell</title><link>https://inet.sh/en/tags/txt/</link><description>Recent content in Txt on inetshell</description><generator>Hugo</generator><language>en</language><lastBuildDate>Fri, 25 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://inet.sh/en/tags/txt/index.xml" rel="self" type="application/rss+xml"/><item><title>2048-bit DKIM: the key does not fit in a 255-character TXT</title><link>https://inet.sh/en/posts/dns/dkim-2048-txt-255-characters/</link><pubDate>Fri, 25 Sep 2026 00:00:00 +0000</pubDate><guid>https://inet.sh/en/posts/dns/dkim-2048-txt-255-characters/</guid><description>How to publish a 2048-bit DKIM key (about 410 characters) when the DNS provider rejects the TXT for exceeding 255: split it into several quoted strings inside the same record. Commands for Route 53 (CharacterStringTooLong), Google Cloud DNS, BIND and Terraform, and verification with dig and openssl.</description><content:encoded><![CDATA[<h2 id="tldr">TL;DR</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nv">PUB</span><span class="o">=</span><span class="k">$(</span>openssl rsa -in dkim.key -pubout -outform DER 2&gt;/dev/null <span class="p">|</span> base64 <span class="p">|</span> tr -d <span class="s1">&#39;\n&#39;</span><span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;v=DKIM1; k=rsa; p=</span><span class="nv">$PUB</span><span class="s2">&#34;</span> <span class="p">|</span> fold -w <span class="m">255</span> <span class="p">|</span> sed <span class="s1">&#39;s/.*/&#34;&amp;&#34;/&#39;</span> <span class="p">|</span> paste -sd<span class="s1">&#39; &#39;</span> -
</span></span></code></pre></td></tr></table>
</div>
</div><p>That prints the value ready to paste into the DNS provider, two quoted strings separated by a space:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">&#34;v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvs7EROOYh35C/1s7M//pIaRvu1XWXzdexgBR2dO7eq1oDw+X08BNJUVUEte3z7os5CNeP7YfZrAqyDJvA59wMK1qul6oHyy7z5P1aB4zNczvO7SZ20HogWjHjzYJ0qwmSUUtjlKvECQzoTCbS/F0gB9rdUZN02MJopDs8YWcohy8oqNLnrflHdxWm6jAb3sSa&#34; &#34;EQReu6iRKKPiXTGUISSetY+iXLo2j/2c5g5ppiIYkUTq58asamMNiCzB7BeF4WNkjz2P+9IJmmtkkJ0M/U4oThUMvBBtQ/XUV4i2N4PGB359G5d/PIMiCj4go2axA4p8ul7Qafbtv0fyPwOIGSojwIDAQAB&#34;
</span></span></code></pre></td></tr></table>
</div>
</div><p>Both go into <strong>the same TXT record</strong>. Whoever verifies DKIM concatenates them with no spaces. If Google Workspace or Microsoft 365 handed you the text and you do not have the private key, it is the same without the <code>openssl</code>: <code>echo &quot;&lt;value&gt;&quot; | fold -w 255 | sed 's/.*/&quot;&amp;&quot;/' | paste -sd' ' -</code>.</p>
<h2 id="the-problem">The problem</h2>
<p>A TXT record is made of one or more <em>character-strings</em>, and each one is capped at <strong>255 bytes</strong> (RFC 1035). The whole record can be much longer; what it cannot have is a single 410-character string.</p>
<table>
  <thead>
      <tr>
          <th>RSA key</th>
          <th>Length of <code>p=</code></th>
          <th>With <code>v=DKIM1; k=rsa; p=</code></th>
          <th>Fits in one string?</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>1024 bits</td>
          <td>216</td>
          <td>234</td>
          <td>Yes</td>
      </tr>
      <tr>
          <td>2048 bits</td>
          <td>392</td>
          <td>410</td>
          <td>No: two are needed</td>
      </tr>
      <tr>
          <td>4096 bits</td>
          <td>736</td>
          <td>754</td>
          <td>No: three</td>
      </tr>
  </tbody>
</table>
<p>Google Workspace and Microsoft 365 generate 2048-bit keys by default, and rightly so: 1024 has been discouraged since RFC 8301. So almost any new DKIM setup today runs into this, and each provider reacts differently:</p>
<table>
  <thead>
      <tr>
          <th>Provider</th>
          <th>What happens with 410 characters in a row</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Route 53</td>
          <td>Rejects it with <code>CharacterStringTooLong</code>, in the console and the CLI</td>
      </tr>
      <tr>
          <td>Google Cloud DNS</td>
          <td>Rejects the value; you have to type the quoted strings yourself</td>
      </tr>
      <tr>
          <td>Cloudflare</td>
          <td>Accepts it and splits it into 255-character chunks on its own</td>
      </tr>
      <tr>
          <td>BIND and most self-hosted servers</td>
          <td>The zone file does not load until you use several strings</td>
      </tr>
  </tbody>
</table>
<p>RFC 6376 (§3.6.2.2) requires verifiers to concatenate the strings before using them, so splitting the key is not a trick: it is the intended format.</p>
<h2 id="per-provider">Per provider</h2>
<h3 id="bind--zone-file">BIND / zone file</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">selector._domainkey  300  IN  TXT  ( &#34;v=DKIM1; k=rsa; p=MIIBIjANBgkq...first part&#34;
</span></span><span class="line"><span class="cl">                                     &#34;second part...IDAQAB&#34; )
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="route-53">Route 53</h3>
<p>In the console, paste both quoted strings into <strong>Value</strong> separated by a space or a line break. From the CLI the value is a single string with escaped quotes:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">aws route53 change-resource-record-sets --hosted-zone-id Z0123456789EXAMPLE --change-batch <span class="s1">&#39;{
</span></span></span><span class="line"><span class="cl"><span class="s1">  &#34;Changes&#34;: [{&#34;Action&#34;: &#34;UPSERT&#34;, &#34;ResourceRecordSet&#34;: {
</span></span></span><span class="line"><span class="cl"><span class="s1">    &#34;Name&#34;: &#34;selector._domainkey.example.com&#34;, &#34;Type&#34;: &#34;TXT&#34;, &#34;TTL&#34;: 300,
</span></span></span><span class="line"><span class="cl"><span class="s1">    &#34;ResourceRecords&#34;: [{&#34;Value&#34;: &#34;\&#34;v=DKIM1; k=rsa; p=...first part\&#34; \&#34;second part...\&#34;&#34;}]
</span></span></span><span class="line"><span class="cl"><span class="s1">  }}]}&#39;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="google-cloud-dns">Google Cloud DNS</h3>
<p>In the console, same format in the data field. With <code>gcloud</code>:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">gcloud dns record-sets create selector._domainkey.example.com. --zone<span class="o">=</span>example-zone <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  --type<span class="o">=</span>TXT --ttl<span class="o">=</span><span class="m">300</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  --rrdatas<span class="o">=</span><span class="s1">&#39;&#34;v=DKIM1; k=rsa; p=...first part&#34; &#34;second part...&#34;&#39;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>With Terraform (<code>google_dns_record_set</code>), a single <code>rrdatas</code> element with escaped quotes:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-hcl" data-lang="hcl"><span class="line"><span class="cl"><span class="n">rrdatas</span> <span class="o">=</span><span class="n"> [&#34;\&#34;v</span><span class="o">=</span><span class="n">DKIM1; k</span><span class="o">=</span><span class="n">rsa; p</span><span class="o">=</span><span class="p">...</span><span class="k">first</span> <span class="k">part</span><span class="err">\</span><span class="s2">&#34; \&#34;second part...\&#34;&#34;</span><span class="p">]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="cloudflare">Cloudflare</h3>
<p>Paste the full value into <strong>Content</strong>; the dashboard splits it on save. When you query it with <code>dig</code> you will see two strings even though you entered one: that is normal.</p>
<h2 id="verifying">Verifying</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">dig +short TXT selector._domainkey.example.com
</span></span></code></pre></td></tr></table>
</div>
</div><p>Expected: <code>&quot;v=DKIM1; k=rsa; p=MIIB...&quot; &quot;...IDAQAB&quot;</code>, two strings, one record. Then check that the key decodes to 2048 bits, which confirms no character was lost at the cut:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">dig +short TXT selector._domainkey.example.com <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  <span class="p">|</span> tr -d <span class="s1">&#39;&#34; \n&#39;</span> <span class="p">|</span> sed -E <span class="s1">&#39;s/.*p=([A-Za-z0-9+/=]+).*/\1/&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  <span class="p">|</span> base64 -d <span class="p">|</span> openssl pkey -pubin -inform DER -noout -text <span class="p">|</span> head -1
</span></span><span class="line"><span class="cl"><span class="c1"># Public-Key: (2048 bit)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>If <code>base64</code> complains, a space slipped inside the key or characters are missing. Finish with a test email and <code>Authentication-Results: ... dkim=pass</code> in the headers; for a closer look, <a href="https://dmarcian.com/dkim-inspector/">dmarcian&rsquo;s DKIM Inspector</a>.</p>
<h2 id="traps">Traps</h2>
<ul>
<li><strong>The cut can go anywhere</strong>, even mid-base64, but <strong>never put spaces inside the key</strong>. The space between the two strings separates strings; it is not data.</li>
<li><strong>Do not double the quotes.</strong> If the panel adds them for you and you paste <code>&quot;...&quot;</code>, <code>dig</code> returns <code>&quot;\&quot;v=DKIM1...\&quot;&quot;</code> and the verifier fails.</li>
<li><strong>One record, not two.</strong> Two separate TXT records with the same name are two independent values, and neither is a valid key.</li>
<li><strong>2048 is the sweet spot.</strong> 4096 means three strings and a DNS answer close to the UDP limit; it works, but gains nothing for DKIM.</li>
<li><strong>Rotation</strong>: publish the new key under a new selector, switch the signer, and delete the old selector after the TTL. Never edit the selector in use.</li>
<li><strong>SPF has the same limit</strong>, but an SPF that does not fit in 255 is usually a sign of too many <code>include:</code>; there the fix is shortening it, not splitting it.</li>
</ul>
<p>References: <a href="https://knowledge.workspace.google.com/admin/security/troubleshoot-dkim-issues">Google Workspace — troubleshoot DKIM issues</a>, <a href="https://repost.aws/knowledge-center/route53-resolve-dkim-text-record-error">AWS re:Post — CharacterStringTooLong</a>, and the <a href="https://www.mailhardener.com/tools/dns-record-splitter">Mailhardener DNS record splitter</a> if you would rather not use <code>fold</code>.</p>
]]></content:encoded></item></channel></rss>