<?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: Michael Doyle</title>
    <description>The latest articles on DEV Community by Michael Doyle (@leaderr700).</description>
    <link>https://dev.to/leaderr700</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%2F4123641%2F90e9cd56-330c-4942-96c0-83811920c0f3.png</url>
      <title>DEV Community: Michael Doyle</title>
      <link>https://dev.to/leaderr700</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/leaderr700"/>
    <language>en</language>
    <item>
      <title>I built an email scorer in one HTML file with zero dependencies. Here is every threshold and where it came from.</title>
      <dc:creator>Michael Doyle</dc:creator>
      <pubDate>Sun, 13 Sep 2026 22:33:22 +0000</pubDate>
      <link>https://dev.to/leaderr700/i-built-an-email-scorer-in-one-html-file-with-zero-dependencies-here-is-every-threshold-and-where-5fkm</link>
      <guid>https://dev.to/leaderr700/i-built-an-email-scorer-in-one-html-file-with-zero-dependencies-here-is-every-threshold-and-where-5fkm</guid>
      <description>&lt;h1&gt;
  
  
  I built an email scorer in one HTML file with zero dependencies. Here is every threshold and where it came from.
&lt;/h1&gt;

&lt;p&gt;I write about B2B sales for a living, which means I read a lot of cold emails and a lot of advice about cold emails. The advice is almost always unfalsifiable. "Keep it short." How short? "Be personal." Measured how?&lt;/p&gt;

&lt;p&gt;So I turned the advice into numbers and put the numbers in a file. One &lt;code&gt;index.html&lt;/code&gt;, about 220 lines, no framework, no build step, no API call. You paste a subject line and a body, it returns a score out of 100 across eight checks.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/leaderr-dev/embed/ByWLPeb?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Live version: &lt;a href="https://leaderr-dev.github.io/proposal-email-scorer/" rel="noopener noreferrer"&gt;Proposal Email Scorer&lt;/a&gt;. Source: &lt;a href="https://github.com/leaderr-dev/proposal-email-scorer" rel="noopener noreferrer"&gt;github.com/leaderr-dev/proposal-email-scorer&lt;/a&gt;, MIT.&lt;/p&gt;

&lt;p&gt;The interesting part is not the UI, it is deciding what is measurable. Here is the whole thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The constraint: everything deterministic
&lt;/h2&gt;

&lt;p&gt;The obvious way to build this in 2026 is to send the email to a model and ask for a score. I did not want that, for three reasons.&lt;/p&gt;

&lt;p&gt;The first is that the same input has to produce the same output. If you paste an email, tweak one word and paste it again, a two point move should mean something. A model gives you a different number on the same input and you learn nothing.&lt;/p&gt;

&lt;p&gt;The second is privacy. People paste real emails about real deals into a tool like this. If there is no network call, there is nothing to explain.&lt;/p&gt;

&lt;p&gt;The third is that it made me define the thresholds instead of hiding behind a model. Every number below is a decision I had to justify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Subject length, 28 to 55 characters
&lt;/h2&gt;

&lt;p&gt;Characters, not words. Mobile clients truncate somewhere around 40 to 55 depending on the device, so 55 is the ceiling. The 28 floor is the softer claim: short subjects correlate with automation because automated subjects are short.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;subj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* 15 points */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* 8 points */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* 6 points */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Over-length scores lower than under-length, because a truncated subject actively hides information.&lt;/p&gt;

&lt;h2&gt;
  
  
  All caps and exclamation marks
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;caps&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b[&lt;/span&gt;&lt;span class="sr"&gt;A-Z&lt;/span&gt;&lt;span class="se"&gt;]{3,}\b&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;bangs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;!&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;{3,}&lt;/code&gt; matters. Without it, "SDR", "CRM", "B2B" and every other sales acronym flags. Three-plus-letter runs still catch acronyms, which is a known false positive I decided to live with, because a subject line stuffed with acronyms is its own problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spam phrases
&lt;/h2&gt;

&lt;p&gt;A 67 entry list, matched as substrings against subject and body joined together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;low&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;SPAM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;low&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SPAM&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SPAM&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scoring is banded rather than linear: zero hits is full marks, one or two is half, three or more is zero. That reflects how filters actually behave. One flagged phrase in an otherwise normal message is noise. Four is a pattern.&lt;/p&gt;

&lt;p&gt;The uncomfortable finding while assembling the list is how much of it is ordinary polite sales writing. "No obligation." "Risk free." "Limited time." These are not things spammers say and salespeople avoid. They are things salespeople say constantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Body length, 50 to 150 words
&lt;/h2&gt;

&lt;p&gt;Under 50 there is not enough to say yes to. Over 150 reply rates fall and keep falling. Over 250 scores near zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading grade
&lt;/h2&gt;

&lt;p&gt;Standard Flesch Kincaid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="mf"&gt;0.39&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;words&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;sentences&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;11.8&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;syllables&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;15.59&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Syllable counting is where this gets approximate. The heuristic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;syl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;a-z&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(?:[^&lt;/span&gt;&lt;span class="sr"&gt;laeiouy&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;es|ed|&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;laeiouy&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;e&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^y/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;aeiouy&lt;/span&gt;&lt;span class="se"&gt;]{1,2}&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It strips silent trailing &lt;code&gt;e&lt;/code&gt;, &lt;code&gt;es&lt;/code&gt; and &lt;code&gt;ed&lt;/code&gt;, then counts vowel groups. It gets "business" and "meeting" right and "queue" wrong. For a whole email the errors wash out, which is why the tool reports a grade to one decimal and not a certified score. Target is 8 or below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Call to action
&lt;/h2&gt;

&lt;p&gt;This is the check I am least happy with, because it is keyword matching:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;CTA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;are you open&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;worth a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;would you be open&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;do you have time&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;15 minutes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quick call&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plus a fallback: if the body ends in a question mark, that counts. It catches most real asks and it will miss an unusually phrased one. The alternative was a model call, which breaks the determinism rule. Keyword matching with a documented blind spot beat a black box with none.&lt;/p&gt;

&lt;h2&gt;
  
  
  Personalisation
&lt;/h2&gt;

&lt;p&gt;Escape the company name, count occurrences:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;co&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;.*+?^${}()|[&lt;/span&gt;&lt;span class="se"&gt;\]\\]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;$&amp;amp;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;g&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The escape is not optional. Real company names contain dots and plus signs, and an unescaped &lt;code&gt;.&lt;/code&gt; matches any character, so "A.B." would match "Abx".&lt;/p&gt;

&lt;p&gt;This check only tells you the name is present. It cannot tell you whether what surrounds it is specific or a mail merge compliment. That is the limit of a rule based tool, and it is the check that matters most, which is the honest tension in the whole project.&lt;/p&gt;

&lt;h2&gt;
  
  
  You to us ratio
&lt;/h2&gt;

&lt;p&gt;Count &lt;code&gt;you|your|yours&lt;/code&gt; against &lt;code&gt;i|we|our|us|my&lt;/code&gt;. Second person should at least match first person. Five points, the lowest weight, because it is a diagnostic rather than a rule. A bad ratio means the email leads with what your company does, and fixing it means rewriting the argument rather than swapping pronouns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Weights
&lt;/h2&gt;

&lt;p&gt;Spam phrases 20, subject length 15, body length 15, CTA 15, subject shouting 10, reading grade 10, personalisation 10, ratio 5. Above 80 send, 60 to 79 fix something first, below 60 do not send.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it deliberately does not do
&lt;/h2&gt;

&lt;p&gt;It does not check DNS records, warm-up state or sending reputation, which matter more than any of the above and cannot be checked from a pasted string. It does not judge whether your offer is any good. And it will not write the email.&lt;/p&gt;

&lt;p&gt;For that last part I use the &lt;a href="https://www.leaderr.io/proposal-generator" rel="noopener noreferrer"&gt;leaderr.io proposal generator&lt;/a&gt;, which takes your site and the prospect's site and drafts the email, and the &lt;a href="https://www.leaderr.io/dossier-generator" rel="noopener noreferrer"&gt;leaderr.io dossier generator&lt;/a&gt; for the company research that makes check seven mean something. Full disclosure, I write for Leaderr, which is also why I had a stack of proposal emails to test this against.&lt;/p&gt;

&lt;p&gt;The repo is MIT. If a threshold looks wrong, the numbers are all in one file and I would rather be argued out of one than keep defending it.&lt;/p&gt;

</description>
      <category>sales</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
