<?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: Givi Pataridze</title>
    <description>The latest articles on DEV Community by Givi Pataridze (@givip).</description>
    <link>https://dev.to/givip</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%2F3937586%2F7cbb0972-0168-4397-8129-076950c2335d.jpg</url>
      <title>DEV Community: Givi Pataridze</title>
      <link>https://dev.to/givip</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/givip"/>
    <language>en</language>
    <item>
      <title>A $169 DIY AC controller that saves 450 kWh a month</title>
      <dc:creator>Givi Pataridze</dc:creator>
      <pubDate>Thu, 24 Sep 2026 20:59:44 +0000</pubDate>
      <link>https://dev.to/givip/a-169-diy-ac-controller-that-saves-450-kwh-a-month-338l</link>
      <guid>https://dev.to/givip/a-169-diy-ac-controller-that-saves-450-kwh-a-month-338l</guid>
      <description>&lt;p&gt;A friend of mine runs a small photo studio, rented out by the hour. There is no staff. Photographers book a slot, punch a door code, and let themselves in with their clients and their gear.&lt;/p&gt;

&lt;p&gt;That last part is the whole problem. You cannot ask a paying client to stand around in a hot room while a wall-mounted air conditioner catches up. And a room full of people under shoot conditions goes stale long before it gets hot, which is why this story involves a CO2 sensor.&lt;/p&gt;

&lt;p&gt;Before this project, the climate was run by whoever was there last. They set the air conditioners with a remote and left. So the units routinely ran all night for an empty room, and just as often the next booking walked into the wrong temperature anyway.&lt;/p&gt;

&lt;p&gt;My friend is not there most days. I am almost never there. But I am the person in our friend group with a soldering-adjacent reputation, so I got volunteered.&lt;/p&gt;

&lt;p&gt;I had never actually soldered anything. That becomes relevant.&lt;/p&gt;

&lt;h2&gt;
  
  
  the plan that was supposed to cost $60
&lt;/h2&gt;

&lt;p&gt;The studio runs on a small budget. That is why its two air conditioners are cheap white-label Chinese splits rather than a known brand, and it is why the proper routes, a commercial climate-automation install or one of the smart-AC-controller gadgets, were never seriously on the table. They cost several times more than what I ended up spending, and what I ended up spending was already too much.&lt;/p&gt;

&lt;p&gt;On July 17 I asked Claude to pick the parts. The requirements: a small &lt;code&gt;ESP32&lt;/code&gt; controller board, Ethernet with power over the cable, a sensor for CO2, temperature, and humidity, and infrared control for the two ACs. Infrared control means teaching a circuit board to click the remote electronically. The AC cannot tell the difference between a remote in a human hand and a small LED blinking the same pattern at it.&lt;/p&gt;

&lt;p&gt;The first estimate came back at about $60.&lt;/p&gt;

&lt;h2&gt;
  
  
  the cart that checked out
&lt;/h2&gt;

&lt;p&gt;By July 20 the plan had grown. Instead of small boards hidden near each AC, I wanted one elegant wall-mounted device with a color screen: temperature in big digits, CO2 next to it, buttons on the front. The cart, all from M5Stack's shop:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;M5Stack Basic v2.7&lt;/td&gt;
&lt;td&gt;$39.90&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ESP32&lt;/code&gt; controller with the color screen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LAN PoE base W5500 v1.2&lt;/td&gt;
&lt;td&gt;$48.50&lt;/td&gt;
&lt;td&gt;Ethernet plus power over the network cable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unit CO2L (&lt;code&gt;SCD41&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;$45.90&lt;/td&gt;
&lt;td&gt;CO2, temperature, humidity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2x Unit IR&lt;/td&gt;
&lt;td&gt;$7.90 each&lt;/td&gt;
&lt;td&gt;infrared emitters, one per AC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grove cables and jumpers&lt;/td&gt;
&lt;td&gt;$10.40&lt;/td&gt;
&lt;td&gt;wiring&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8kktu08gyl0qon8w43zn.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8kktu08gyl0qon8w43zn.webp" alt="The order as it arrived: the boxed PoE base W5500, sealed packets of Grove cables and Grove-to-Dupont jumpers, and the Unit CO2L sensor with its orange connectors" width="760" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Total: $169.70 (including shipping). Claude confirmed the cart item by item. Its verdict: checks out, safe to order.&lt;/p&gt;

&lt;p&gt;Every item on that list was correct. The cart was fine.&lt;/p&gt;

&lt;p&gt;It just wasn't the plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  what arrived, and what didn't fit
&lt;/h2&gt;

&lt;p&gt;The boxes arrived August 13, and every part was individually fine. The catch showed up during assembly, and it was not a missing part. It was a budget problem of a different kind: &lt;strong&gt;one small &lt;code&gt;ESP32&lt;/code&gt; does not have enough free pins and communication channels to run everything at once.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Think of the board's pins as outlets on a power strip, except some devices refuse to share and some insist on a specific outlet. The Ethernet chip in the PoE base claims the &lt;code&gt;SPI&lt;/code&gt; bus plus a handful of &lt;code&gt;GPIO&lt;/code&gt; pins. The color screen needs that same &lt;code&gt;SPI&lt;/code&gt; bus plus pins of its own. The CO2 sensor takes the &lt;code&gt;I2C&lt;/code&gt; port. And each infrared unit wants its own direct &lt;code&gt;GPIO&lt;/code&gt; line, because infrared needs exact microsecond timing that can't be routed through a shared connection.&lt;/p&gt;

&lt;p&gt;Ethernet, screen, sensor, and two IR channels together simply do not fit on this board.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fodppfr8ihsslao8ob7zc.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fodppfr8ihsslao8ob7zc.webp" alt="The underside of the M5Stack controller, every pin labelled in colour coded strips, with jumper wires pushed onto the G16, G17 and G36 headers" width="800" height="554"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Something had to lose.&lt;/p&gt;

&lt;h2&gt;
  
  
  what got cut
&lt;/h2&gt;

&lt;p&gt;Ethernet lost first. The $48 PoE base stayed in the build, but only as a power supply: the network cable delivers electricity and nothing else, and data moved to Wi-Fi permanently. There is a comment in the shipped config that says exactly that. I paid $48 for a power brick.&lt;/p&gt;

&lt;p&gt;The IR receive channels lost second. The infrared units run transmit-only; I wired up a receiver when I needed to record the real remote's signals.&lt;/p&gt;

&lt;p&gt;Then came the second catch. The screw terminals on the PoE base, the natural exit point for the IR wiring, are not connected to anything from the factory. Power, ground, and the control pins simply do not reach them. The usable pads exist only inside the stack. Claude and I walked through every no-solder alternative, and each one died. A hub is the wrong kind of connection: IR needs a direct &lt;code&gt;GPIO&lt;/code&gt; with a &lt;code&gt;38 kHz&lt;/code&gt; carrier and microsecond timing, and every hub in this ecosystem is an &lt;code&gt;I2C&lt;/code&gt; device that physically cannot do that. A $6 pass-through module needs soldering to attach anyway. Claude's summary: the six terminals are a blank to be soldered, not a ready breakout.&lt;/p&gt;

&lt;p&gt;I had specified this build as no-soldering. Every path led back to a soldering iron. This is the point where I swore at my AI assistant, and its answer boiled down to: the parts are all fine, the sentence missing at order time was that wiring the IR units out of this stack means fifteen minutes with an iron.&lt;/p&gt;

&lt;p&gt;It was right, which did not help.&lt;/p&gt;

&lt;h2&gt;
  
  
  four wires
&lt;/h2&gt;

&lt;p&gt;So I bought a soldering iron, the first one I have ever owned, and practiced on a dead board.&lt;/p&gt;

&lt;p&gt;The actual job was four jumper wires from the base's internal pads to the screw terminals: ground, &lt;code&gt;5V&lt;/code&gt;, and the two IR signal lines, &lt;code&gt;G16&lt;/code&gt; and &lt;code&gt;G17&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It worked.&lt;/p&gt;

&lt;p&gt;Four wires. That was the entire distance between one elegant device with a screen and a stack of parts that talk past each other.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft7qdecri705hoa8rwqbn.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft7qdecri705hoa8rwqbn.webp" alt="The PoE base held in one hand, four blue jumper wires soldered from its inner pads across to the orange screw terminal block, with a soldering station and multimeter on the bench behind" width="680" height="746"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  an air conditioner that spoke no known language
&lt;/h2&gt;

&lt;p&gt;Now the software half. The ACs are branded "Wagner," a regional white-label name, remote model &lt;code&gt;G4W-18BHR&lt;/code&gt;. The obvious theory is that a no-name split is one of the usual suspects inside: &lt;code&gt;Gree&lt;/code&gt;, &lt;code&gt;Midea&lt;/code&gt;, the &lt;code&gt;Coolix&lt;/code&gt; protocol family. ESPHome's IR climate support covers all of them out of the box. You capture one button press, the library names the protocol, and you're done.&lt;/p&gt;

&lt;p&gt;I got an early false victory. The first remote I captured, to test the receiver wiring, was my home AC's remote. It decoded instantly as &lt;code&gt;Coolix&lt;/code&gt;. For a while the plan was: it's Coolix, config done.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F23wth6fmserehcofoqwq.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F23wth6fmserehcofoqwq.webp" alt="An infrared unit resting face down on an air conditioner remote on the desk, wired back to the controller, recording the codes each button press sends" width="700" height="1244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The actual remote was not the same remote.&lt;/p&gt;

&lt;p&gt;The Wagner remote matched none of the roughly ten ready-made protocol decoders I tried. Gree in all its variants, Coolix, Midea, &lt;code&gt;TCL112&lt;/code&gt;, everything. Nothing recognized it. Somewhere a factory had shipped an air conditioner speaking an infrared dialect none of the usual open-source decoders recognized.&lt;/p&gt;

&lt;h2&gt;
  
  
  reverse-engineering the ir protocol from 97 recordings
&lt;/h2&gt;

&lt;p&gt;So we decoded it from scratch: me pressing buttons, Claude staring at the timings. I captured 97 infrared frames, and on September 1 the pattern gave in.&lt;/p&gt;

&lt;p&gt;The result, now documented in the project repo: a &lt;code&gt;38 kHz&lt;/code&gt; carrier, which is the specific flicker rate the AC's receiver eye is tuned to. A 96-bit frame, 12 bytes, sent least-significant-bit first. A &lt;code&gt;6180&lt;/code&gt; microsecond header pulse announcing each message. Temperature encoded as the value minus 16 in byte 9, so &lt;code&gt;24°C&lt;/code&gt; travels as an 8. Fan speeds numbered backward, &lt;code&gt;1&lt;/code&gt; for max and &lt;code&gt;3&lt;/code&gt; for min, because of course they are. And a checksum, the frame's built-in way of noticing corruption, that is nothing fancier than the sum of the first 11 bytes modulo 256.&lt;/p&gt;

&lt;p&gt;No existing ESPHome component spoke it, so we wrote one: a custom decoder and encoder, built largely with Claude doing the byte arithmetic and me doing the button pressing.&lt;/p&gt;

&lt;h2&gt;
  
  
  proving it
&lt;/h2&gt;

&lt;p&gt;A decoded protocol is a theory until it round-trips. We re-encoded every captured frame from the formula and compared the output byte for byte against the recordings. The first run scored 44 of 45; the single mismatch was a transitional frame caught mid-mode-switch. The control run scored &lt;strong&gt;52 of 52&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Then the loop closed itself in the most satisfying way available. On the first live transmission, the device's own receiver caught the frame its own transmitter had just sent, and decoded it correctly. The bytes matched a recording of the real remote for the same state exactly.&lt;/p&gt;

&lt;p&gt;On September 4 the real indoor unit obeyed: on, off, factory turbo.&lt;/p&gt;

&lt;p&gt;The protocol was closed.&lt;/p&gt;

&lt;h2&gt;
  
  
  the bug that wasn't
&lt;/h2&gt;

&lt;p&gt;One debugging story worth its space. The IR LED on the emitter module is fed through a &lt;code&gt;150 ohm&lt;/code&gt; resistor, about &lt;code&gt;23 mA&lt;/code&gt;, against the hundreds of milliamps a real remote pushes. Range is roughly two meters and the beam is narrow.&lt;/p&gt;

&lt;p&gt;One day the AC stopped responding. I burned hours on a plausible hypothesis: maybe a single frame wasn't enough and the command needed repeating, the way some remotes hammer their message several times. Four-copy frames worked once, by coincidence, then failed too. The actual cause, the entire time, was that the LED was pointed slightly off axis. Aimed properly, a single frame was enough, exactly like the factory remote.&lt;/p&gt;

&lt;p&gt;With a weak emitter, &lt;strong&gt;aim matters more than distance&lt;/strong&gt;. The AC was never ignoring me. I was talking past it.&lt;/p&gt;

&lt;h2&gt;
  
  
  controlling a split system remotely, without the remote
&lt;/h2&gt;

&lt;p&gt;Here is the finished behavior, running on the wall with nobody in the building, no server and no phone app required to keep it running.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr764tdfkt6lk3lkzzqs5.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr764tdfkt6lk3lkzzqs5.webp" alt="The finished controller on the wall, its screen showing the room temperature in large digits with CO2 in ppm and humidity underneath, an Ethernet cable feeding it power from below" width="191" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The room sensor is the thermostat, not the AC's own one, and it updates every 60 seconds. In summer, cooling switches on at &lt;code&gt;24.0°C&lt;/code&gt; and off at &lt;code&gt;23.0°C&lt;/code&gt;. In winter, heating switches on at &lt;code&gt;18.0°C&lt;/code&gt; and off at &lt;code&gt;22.0°C&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The trick that makes a cheap split behave is the setpoint. The box deliberately commands the AC to an overshoot target, &lt;code&gt;18°C&lt;/code&gt; when cooling and &lt;code&gt;24°C&lt;/code&gt; when heating, so the AC's own thermostat never decides it's done and starts dawdling. The box itself cuts the unit off when the room sensor says done. The AC works at full tilt or not at all, and the room, not the machine, is the judge.&lt;/p&gt;

&lt;p&gt;Every 15 minutes the box re-sends its current command. Anyone who fixes the climate with a physical remote gets quietly overruled within a quarter of an hour. The remotes still work; they just don't win.&lt;/p&gt;

&lt;p&gt;The night schedule is the money part. Both units switch off from &lt;code&gt;23:00&lt;/code&gt; to &lt;code&gt;08:30&lt;/code&gt;, every day, because night bookings are rare and an empty room does not need conditioning. A frost guard heats if the room falls to &lt;code&gt;10°C&lt;/code&gt; and stops at &lt;code&gt;13°C&lt;/code&gt;. The rare night visitor presses a button on the box to suspend the schedule.&lt;/p&gt;

&lt;p&gt;Three buttons total: cycle auto/manual/off, toggle the night schedule, and a 180-minute boost at the coldest setpoint and max fan. The screen shows temperature in half-screen digits and CO2 color-coded: green below &lt;code&gt;1000 ppm&lt;/code&gt;, yellow to &lt;code&gt;1500&lt;/code&gt;, red above. Red means open a window, which in a room full of people under shoot lights happens well before anyone feels warm.&lt;/p&gt;

&lt;p&gt;And a failsafe: if the temperature sensor drops out, the box switches both ACs off rather than run blind. Turbo and off are the only commands it will still send without sensor data. There is no server, no cloud, no app. If Wi-Fi dies, the logic keeps running on the device.&lt;/p&gt;

&lt;h2&gt;
  
  
  turning the ac off at night: what it saves
&lt;/h2&gt;

&lt;p&gt;I did not install an electricity meter, so what follows is arithmetic on stated assumptions, not a measurement. The assumptions are in the open; disagree with any of them and the number moves.&lt;/p&gt;

&lt;p&gt;The remote's model number marks these as 18,000 BTU-class splits, which draw roughly &lt;code&gt;1.5 to 1.8 kW&lt;/code&gt; while the compressor runs. Left on overnight, a split's compressor cycles; call it running about half the time. The schedule removes 9.5 hours a night, on two units.&lt;/p&gt;

&lt;p&gt;Two units, 9.5 hours, about 1.65 kW, half duty: roughly 15 kWh per night, with a fair range of 12 to 19. Per month, roughly 450 kWh, range about 350 to 570.&lt;/p&gt;

&lt;p&gt;Pricing is illustrative arithmetic only: at $0.10 per kWh that is about $45 a month, so the $166.40 of hardware pays for itself in around four months on the night schedule alone, before counting whatever the daytime hysteresis saves. Your tariff will differ. The shape of the number will not: the biggest feature in this build, the one that actually saves electricity, is the off switch.&lt;/p&gt;

&lt;h2&gt;
  
  
  the same build, cheaper: no screen, no PoE
&lt;/h2&gt;

&lt;p&gt;Now the honest postscript. Knowing everything above, here is what I would actually build.&lt;/p&gt;

&lt;p&gt;The roughly $50 version, no soldering. Two M5Stack Atom Lite boards, under $10 each, one stuck next to each AC. The IR LED is already on the board, so the entire soldering saga in this post evaporates. Add one CO2 sensor unit on the Grove port of one Atom (the &lt;code&gt;SCD40&lt;/code&gt; version was $33.90 when I checked in July; the &lt;code&gt;SCD41&lt;/code&gt; in my build costs more). Power both from any USB phone charger. Run the same ESPHome logic over Wi-Fi. No screen: the numbers live in ESPHome's built-in web page, readable on any phone. No PoE: the phone charger is the power supply. This is the version I should have started with.&lt;/p&gt;

&lt;p&gt;The roughly $20 version, if you can solder a little. Any generic &lt;code&gt;ESP32&lt;/code&gt; dev board, $4 to $6. An IR LED plus a transistor and two resistors, under a dollar in parts, is the whole IR side. A basic temperature and humidity sensor, a few dollars, covers the thermostat. That gets you the hysteresis, the overshoot trick, and the night schedule: everything in this post except the CO2 number.&lt;/p&gt;

&lt;p&gt;Where not to cheap out: the CO2 sensor. A real CO2 sensor, photoacoustic or NDIR like the &lt;code&gt;SCD40&lt;/code&gt; and &lt;code&gt;SCD41&lt;/code&gt;, is the one part that costs real money, $30 and up, and it costs that for a reason. Cheaper boards advertise &lt;code&gt;eCO2&lt;/code&gt;, which is an estimate derived from other gases, not a CO2 measurement. That warning surfaced in my July parts research and is why the SCD41 is in the box. If the room-full-of-people number matters to you, pay for it. If it doesn't, drop it, and the whole build gets very cheap.&lt;/p&gt;

&lt;p&gt;What did the $169.70 actually buy over the $50 version? A screen on the wall, so the numbers are visible without a phone. Three physical buttons. And $48 of Ethernet that carries no data. The logic, the protocol work, and the savings are identical on the cheap builds.&lt;/p&gt;

&lt;p&gt;I would build the $50 version today. The $169.70 version is what it cost me to learn that.&lt;/p&gt;

&lt;p&gt;Because here is the thing the whole project turns on: not one expensive part ever failed. The board was fine, the base was fine, the sensor was fine, and Claude's cart really did check out, line by line. What nobody counted was the connections: the shared bus, the pin budget, the six terminals that were a blank.&lt;/p&gt;

</description>
      <category>diy</category>
      <category>hardware</category>
      <category>iot</category>
    </item>
    <item>
      <title>BMAD Ate My Month: When Spec-Driven Development Is Too Much</title>
      <dc:creator>Givi Pataridze</dc:creator>
      <pubDate>Tue, 22 Sep 2026 08:20:39 +0000</pubDate>
      <link>https://dev.to/givip/bmad-ate-my-month-when-spec-driven-development-is-too-much-5806</link>
      <guid>https://dev.to/givip/bmad-ate-my-month-when-spec-driven-development-is-too-much-5806</guid>
      <description>&lt;p&gt;On September 5 I deleted 1,782 files from my autopilot's repository in one commit. Agents, templates, workflow configs, a PRD (Product Requirements Document), an architecture document, a story backlog longer than most novels. About 16 MB of process, and not one line of product.&lt;/p&gt;

&lt;p&gt;Typing that commit message felt better than anything I shipped that month.&lt;/p&gt;

&lt;p&gt;Some context if you are new here. The autopilot is an autonomous coding system I built and have been running for months: it receives GitHub webhooks and runs headless Claude Code sessions that write, review, and merge pull requests without me at the keyboard. I have told its story before, from &lt;a href="https://pataridze.me/ai-autopilot-that-ships-code-while-i-sleep" rel="noopener noreferrer"&gt;building it&lt;/a&gt; to &lt;a href="https://pataridze.me/the-day-my-autopilot-ran-out-of-tokens" rel="noopener noreferrer"&gt;the day it ran out of tokens&lt;/a&gt;. This post is about the question those posts skipped: how work should be planned before an agent ever sees it.&lt;/p&gt;

&lt;p&gt;The industry has an answer to that question. SDD (Spec-driven development): write the specification first, make it the contract, and let the agents implement against it. BMAD is that idea at full weight, an entire agile organization in software, with AI analysts, architects, product managers, and developers, and a workflow that runs them in order. For four weeks, it planned my product.&lt;/p&gt;

&lt;p&gt;This post is about what that month cost, and the embarrassingly small thing that actually fixed the problem BMAD was supposed to fix. If you run coding agents and your PRs keep turning into hostage negotiations, this is for you. I got this wrong twice before getting it right, and both wrong answers looked smart at the time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The failure that started everything
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffmk76rl2ve87ogiquzao.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffmk76rl2ve87ogiquzao.webp" alt="bmad-s1-two-laptops" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You know this failure. You have probably committed it this week.&lt;/p&gt;

&lt;p&gt;You are busy, the agent is capable, so you file a one-line issue: remove this, add that, make it configurable. The agent reads your line and builds either the wrong thing or a monument to the right one. Then the reviewer model, the expensive one you hired precisely to catch problems, catches the problem. In review. After the work exists. After the money is spent.&lt;/p&gt;

&lt;p&gt;My worst case: a cleanup that should have been a quiet deletion collected sixty comments across ten review rounds. Two models arguing with each other, round after round, every round billed to me. Then I closed the pull request without merging it.&lt;/p&gt;

&lt;p&gt;Sixty comments. Ten rounds. Nothing shipped. And the whole argument was downstream of one line I wrote in thirty seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt 1: the machine tried to fix itself
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftjiud43sdxsytscjb1g1.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftjiud43sdxsytscjb1g1.webp" alt="bmad-s2-printer-loop" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My autopilot's answer to "the PRs are too big" was, I swear, more autopilot.&lt;/p&gt;

&lt;p&gt;It generated a size gate: a &lt;code&gt;scope&lt;/code&gt; agent that estimated the diff an issue would produce, and above a budget carved the work into ordered sub-issues. Almost six thousand lines of new code, to enforce a line budget on future code. I did not design this. The machine did, and the design was even accurate about the disease. Its own PR body diagnosed that large PRs drive the review churn.&lt;/p&gt;

&lt;p&gt;And still it was attacking the symptom. The gate measured work &lt;em&gt;after&lt;/em&gt; the intent was already written badly. Splitting work after it exists is triage, not planning. By the time there is a diff to estimate, the mistake is old. It was made in the issue.&lt;/p&gt;

&lt;p&gt;I never merged it. The dangerous part is how reasonable it looked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt 2: BMAD
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv6vvrjf5wy7pggm5vmxv.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv6vvrjf5wy7pggm5vmxv.webp" alt="bmad-s3-mission-control" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I found BMAD through a podcast on spec-driven development. One of the guests was a BMAD contributor, and everything he said sounded solid. I wanted solid. I was tired of arguing with my own pull requests.&lt;/p&gt;

&lt;p&gt;So the day after rejecting the machine's six-thousand-line fix, I installed a 1,782-file one.&lt;/p&gt;

&lt;p&gt;BMAD planned my product the way an enterprise plans a satellite launch. A 13,397-word PRD. A 19,867-word architecture spine. An &lt;code&gt;epics.md&lt;/code&gt; backlog that reached 43,062 words. Nine epics, 86 stories, every one with acceptance criteria. Reading the plan felt like adult supervision had finally arrived.&lt;/p&gt;

&lt;p&gt;Five days in, an implementation-readiness assessment found one critical omission and three major planning defects, and blocked all further implementation. Sit with that. The plan failed a review of the plan. The fix, approved the same day, grew the plan to 91 stories. The product had not moved.&lt;/p&gt;

&lt;p&gt;Then the loop started, and I met the real bill. A typical story burned one to two million tokens. One story hit around thirty million. Thirty million tokens, one story. Maybe I misconfigured something; honestly, I probably did. But look at what my config had to become in self-defense: a four-million-token budget per story, a 210-minute session timeout, a hard cap of seven review cycles, nudge budgets for sessions that stall without a result. Those are not settings. Those are restraining orders.&lt;/p&gt;

&lt;p&gt;To be fair, &lt;code&gt;bmad-loop&lt;/code&gt; itself is genuinely well built. The TUI is impressive. The quality bar is real; the reviews caught real defects. In four weeks, 23 stories were implemented and reviewed through it. Six more finished their code and parked themselves as "awaiting operator", waiting for things only a human can do.&lt;/p&gt;

&lt;p&gt;But my product was young and changed constantly, and every change created homework. Update the PRD. Update the architecture. Update the backlog. The documents needed to be current before the code was allowed to move, so the code moved at the speed of the documents.&lt;/p&gt;

&lt;p&gt;I was supposed to operate an autonomous system. I had become its secretary.&lt;/p&gt;

&lt;p&gt;My verdict is not that BMAD is bad. BMAD is solid. Too solid. For an established product with a stable spec, that bar might be exactly right. For a product still finding its shape, the bar killed the only metric that mattered: time to release. On September 5 the whole kit left in one commit, and the release line moved forward the same day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt 3: steal the good part, skip the religion
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzzu9ac5dc8zgupaj7uzg.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzzu9ac5dc8zgupaj7uzg.webp" alt="bmad-s4-pinned-card" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is what actually worked, and what I would tell you to do instead of either of my failures.&lt;/p&gt;

&lt;p&gt;I did not adopt another framework. I took the one thing from the spec-driven world that had earned its keep, Spec Kit's way of expressing intent, and forced it into &lt;code&gt;add-autopilot-issue&lt;/code&gt;, the skill I already used to file work. Spec Kit is compact where BMAD is encyclopedic, and it asks quite exactly the right questions: what changes, for whom, how you will know it worked.&lt;/p&gt;

&lt;p&gt;The mechanics that now run my intake, all of them small:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every story issue carries a pinned spec reference: &lt;code&gt;Spec: owner/repo@sha:path#user-story-N&lt;/code&gt;, full 40-character SHA required. Coder and reviewer read that exact version, so neither can move the goalposts mid-session by editing the spec.&lt;/li&gt;
&lt;li&gt;One user story becomes one issue. Two or more become a parent epic issue with one issue per story and an &lt;code&gt;epic/NNN-&amp;lt;slug&amp;gt;&lt;/code&gt; integration branch.&lt;/li&gt;
&lt;li&gt;A story with more than 12 tasks gets split before it is filed.&lt;/li&gt;
&lt;li&gt;Reviews run against the pinned spec with a BLOCKING/SHOULD/NIT rubric, so "I don't like it" and "this violates the spec" stop being the same comment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And one rule no code enforces, because it is mine: when I write an issue, I aim for work around 300 lines of non-test code. Small enough that a session cannot wander, small enough that a review cannot spiral.&lt;/p&gt;

&lt;p&gt;That is the entire fix. A reworked skill and a pinned line of text. The smallest thing I tried, and the only one still on &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decided before it starts
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk7euj5oolc4q619y0gkg.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk7euj5oolc4q619y0gkg.webp" alt="bmad-s5-notebook" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Three attempts, one lesson wearing three costumes. &lt;strong&gt;The quality and cost of an autonomous coding session are decided before it starts: by how precisely the intent is expressed, and by how small the work arrives.&lt;/strong&gt; The size gate tried to enforce that in code, after intent. BMAD tried to enforce it in documents, on top of intent. What worked was just doing it: saying precisely what I want, in pieces small enough to survive contact with review.&lt;/p&gt;

&lt;p&gt;One more observation, offered as observed because I have not measured it and it is clearly not linear: the better the intent is expressed, the cheaper the model that can execute it.&lt;/p&gt;

&lt;p&gt;And a verdict, for whoever is weighing BMAD right now. I did not dabble. I ran the full, fundamental approach, the way it is meant to be run, and for me it did not work: too long, too expensive. For an enterprise with a stable spec and a tolerance for ceremony, that same weight may be exactly right. My projects move fast, and BMAD could not keep up with them. So the experiment is closed. I will not run it on any of my projects for now; more flexible approaches carry its best idea at a fraction of the cost.&lt;/p&gt;

&lt;p&gt;That is what those 1,782 deleted files were. Not a failed tool.&lt;/p&gt;

&lt;p&gt;A closed experiment.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>automation</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to Send Email via Claude Desktop</title>
      <dc:creator>Givi Pataridze</dc:creator>
      <pubDate>Wed, 10 Jun 2026 08:23:17 +0000</pubDate>
      <link>https://dev.to/goodsender/how-to-send-email-via-claude-desktop-549f</link>
      <guid>https://dev.to/goodsender/how-to-send-email-via-claude-desktop-549f</guid>
      <description>&lt;h2&gt;
  
  
  How to Send Email from Claude — Free, in Two Minutes
&lt;/h2&gt;

&lt;p&gt;Two minutes from now, Claude Desktop will send a real email through your own account. This guide is for Claude Desktop users with a GoodSender account who want to wire up email via MCP. GoodSender is free for the first 100,000 emails per month, no credit card required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Claude Desktop installed.&lt;/li&gt;
&lt;li&gt;A GoodSender account — &lt;a href="https://goodsender.com" rel="noopener noreferrer"&gt;sign up free, no credit card&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Install the MCP Server
&lt;/h2&gt;

&lt;p&gt;Download &lt;code&gt;goodsender.mcpb&lt;/code&gt; from the &lt;a href="https://github.com/good-sender/mcp/releases/latest" rel="noopener noreferrer"&gt;latest GitHub release&lt;/a&gt;. Double-click it. Claude Desktop registers the server automatically.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93robmuphzy4s4jytey5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93robmuphzy4s4jytey5.png" alt="Claude Desktop showing the GoodSender MCP server listed under connected tools" width="800" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using a different AI client like Cursor? You'll need the Docker or manual binary path — see the &lt;a href="https://github.com/good-sender/mcp" rel="noopener noreferrer"&gt;MCP server docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Add Your API Key
&lt;/h2&gt;

&lt;p&gt;Grab your API key from the GoodSender dashboard. Paste it into the configuration prompt Claude Desktop shows after install.&lt;/p&gt;

&lt;p&gt;Before sending, make sure you've also verified your sending domain in the GoodSender dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flow 1: Compose and Send a Custom Template
&lt;/h2&gt;

&lt;p&gt;In Claude Desktop, ask Claude to create a "weekly update" template using the MCP template composer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Create a new email template called "Weekly Update" with a subject line "Your weekly update from Awesome App" with a futuristic design using GoodSender MCP&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Claude opens the MCP template composer and builds the template with your variables. Once you're happy with it, ask Claude to send it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7beesyb593c21alm4rms.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7beesyb593c21alm4rms.png" alt="Claude Desktop showing the MCP template composer" width="799" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Send the Weekly Update template to me at &lt;a href="mailto:you@example.com"&gt;you@example.com&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy5m5zrfsqpxdncu9vv3h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy5m5zrfsqpxdncu9vv3h.png" alt="Test email successfully delivered" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A note on consent:&lt;/strong&gt; Custom sends to recipients require the Permission Loop. GoodSender requests consent from the recipient first — outbound messages queue locally until consent is granted. Once a recipient approves, subsequent sends from your domain go through instantly. That earned permission is what keeps deliverability compounding rather than degrading over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flow 2: Send a Transactional OTP Email
&lt;/h2&gt;

&lt;p&gt;Transactional templates are the contrast case — no template setup, no consent step, and they fire instantly. In Claude Desktop, paste this prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Send an OTP code to me at &lt;a href="mailto:you@example.com"&gt;you@example.com&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Claude picks the GoodSender MCP, calls the transactional template endpoint, and the email lands in your inbox instantly. Transactional templates ship without a consent step, so there's no queue and no setup — the send goes through the moment Claude calls the tool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd5lfiw4c3s7x8zwkxvp8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd5lfiw4c3s7x8zwkxvp8.png" alt="OTP email successfully delivered" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Flow 3: Schedule a One-Time Send
&lt;/h2&gt;

&lt;p&gt;Claude Desktop (in Cowork mode) has a built-in scheduler. You can use it to schedule a one-time send of the Weekly Update template for Monday at 10am — GoodSender's MCP handles the actual send when the scheduled time fires.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Schedule a one-time send of the Weekly Update template to &lt;a href="mailto:you@example.com"&gt;you@example.com&lt;/a&gt; for Monday at 10am. Use headline "Monday briefing" and "Here's what's coming up this week."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8x53nef1yntgic65e8zu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8x53nef1yntgic65e8zu.png" alt="Claude Desktop (Cowork mode) showing the scheduled task confirmation" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Can Do Next
&lt;/h2&gt;

&lt;p&gt;Now that you've got email working from Claude, the best thing to do is try it with your own use case. Send an OTP to a real user, schedule a weekly update, or write an email in Markdown and watch it render perfectly across 90+ inbox clients. The setup is already done — the rest is just asking Claude.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why GoodSender for This
&lt;/h2&gt;

&lt;p&gt;Free for 100,000 emails per month, no credit card. Consent and engagement are built into the API — the Permission Loop gates custom sends on explicit recipient consent, and the Engagement Check monitors recipient activity over time — so deliverability compounds rather than degrades. It runs on the same IP infrastructure Laneful uses for the world's largest senders.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;

&lt;p&gt;Sign up and grab your free API key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://goodsender.com" rel="noopener noreferrer"&gt;Get your free API key →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>claudedesktop</category>
      <category>permissionloop</category>
      <category>emailapi</category>
    </item>
    <item>
      <title>How to Improve Email Deliverability in 2026: Stop Fighting for the Inbox and Start Earning It</title>
      <dc:creator>Givi Pataridze</dc:creator>
      <pubDate>Tue, 02 Jun 2026 19:39:02 +0000</pubDate>
      <link>https://dev.to/goodsender/how-to-improve-email-deliverability-in-2026-stop-fighting-for-the-inbox-and-start-earning-it-5gmg</link>
      <guid>https://dev.to/goodsender/how-to-improve-email-deliverability-in-2026-stop-fighting-for-the-inbox-and-start-earning-it-5gmg</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd7lpbpnlkabp2n6cevmr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd7lpbpnlkabp2n6cevmr.png" alt="Abstract illustration of an email envelope rising upward through layered filters toward a glowing inbox, symbolizing earned deliverability" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You did everything right. You set up DKIM. You verified your domain. You wrote a clean SPF record, layered DMARC on top, and kept your recipient list tidy by hand. And your password-reset emails still land in spam.&lt;/p&gt;

&lt;p&gt;The instinct, at this point, is to look for another DNS record to fix. To re-read the Postmark blog. To check whether the alignment mode in your DMARC policy is &lt;code&gt;relaxed&lt;/code&gt; when it should be &lt;code&gt;strict&lt;/code&gt;. That instinct is wrong — or, more precisely, it ran out of useful work several steps ago.&lt;/p&gt;

&lt;p&gt;Deliverability is not a configuration problem. It is a reputation problem. And reputation is not something you configure once and forget; it is something you earn, continuously, through the behavior of the people who receive your mail. The authentication checklist is the floor. Everything that actually decides whether you reach the inbox happens after the SMTP handshake.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Standard Advice Isn't Enough Anymore
&lt;/h2&gt;

&lt;p&gt;The checklist is necessary. It is also not differentiating. DKIM, SPF, DMARC, a custom sending domain, sane bounce handling — every credible email provider can set this up for you, and many will do it automatically. That is not the interesting part. Mailbox providers treat authentication as a precondition for being considered at all, not as a signal of trustworthiness. A spammer can pass DKIM.&lt;/p&gt;

&lt;p&gt;The more uncomfortable problem is structural. Most email API customers share IP pools with thousands of other senders, and they do not get to choose who those other senders are. Some of them have poor list hygiene. Some buy lists. Some are running outright abuse campaigns until the provider catches them. While they are sending, every sender in the pool pays — through higher spam placement rates, throttling, and occasional blocks. Everyone's reputation rises and falls together, so good senders end up paying for bad senders' mistakes.&lt;/p&gt;

&lt;p&gt;This is not an accident of how the market evolved. It is baked into the pricing. SendGrid's Essentials plan starts at $19.95/month (up to 100,000 emails); serious 100K usage typically pushes customers onto Pro at $89.95/month. Mailgun charges around $75 at 100K. Postmark sits at roughly $134. Resend lands at $35. Those prices, in part, absorb the cost of cold-email abuse across the shared pool — complaint handling, reputation remediation, abuse-team overhead. Every customer pays for those problems whether or not they cause them.&lt;/p&gt;

&lt;p&gt;The 2026 context makes this worse, not better. Gmail and Yahoo tightened bulk sender requirements in February 2024 — for senders sending 5,000 or more messages per day to personal Gmail or Yahoo accounts, one-click unsubscribe headers (RFC 8058), stricter authentication enforcement, and a spam-complaint rate kept under roughly 0.3% are now mandatory. Google escalated enforcement through 2025, moving from temporary delays toward outright rejections for repeat offenders. The direction of travel is toward stricter enforcement, not looser. Passing authentication is increasingly the minimum bar to avoid outright rejection — not a path to the inbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Mailbox Providers Actually Reward
&lt;/h2&gt;

&lt;p&gt;The positive case is worth stating directly, because it changes what you optimize for.&lt;/p&gt;

&lt;p&gt;Mailbox providers care primarily about engagement signals. Opens, clicks, replies, and "move to inbox" actions tell them that recipients want the mail. Spam complaints, deletions without opening, and "mark as spam" actions tell them the opposite. Reputation is a running score, not a one-time certification — it compounds in both directions, and the input is the behavior of your recipients.&lt;/p&gt;

&lt;p&gt;Complaint rates are the fastest way to damage that score. A single spam complaint from someone who never affirmatively asked to hear from you is disproportionately damaging, and you cannot rely on feedback loops alone to catch the problem. Gmail does not run a traditional FBL; the protection mechanism there is aggregate reputation surfaced through Google Postmaster Tools. By the time a complaint registers as a number on a dashboard, the damage is already underway.&lt;/p&gt;

&lt;p&gt;List decay is the slower, quieter killer. Recipients who stop engaging but stay on your list become a liability. They don't complain. They just don't open. Sending consistent volume to recipients who never engage is itself a signal that you are not sending wanted mail. Most senders never notice this happening, because their email API surfaces engagement data in a dashboard nobody opens — not as something the system acts on.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Levers That Actually Move Deliverability
&lt;/h2&gt;

&lt;p&gt;What follows is a principles-first playbook. Each lever can be implemented manually on any platform; the question is whether you want to build it yourself or use infrastructure that enforces it for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lever 1: Permission before the first send
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fosqo3tr7xmksou8b0sng.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fosqo3tr7xmksou8b0sng.png" alt="Illustration of a locked gate with a glowing green checkmark appearing as it opens, representing explicit recipient consent as a hard gate before email delivery" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The highest-leverage thing you can do for deliverability is to make sure every recipient on a custom send list has explicitly consented to receive mail from you.&lt;/p&gt;

&lt;p&gt;This is not the same as "they gave us their email address at signup." It means the recipient has affirmatively opted in to receive this type of communication from this sender, and you have a record of it. Mechanically, a consented recipient is far more likely to open, click, and not complain. Every send to a consented list is a positive reputation signal. Every send to a list you assembled from form submissions and CRM exports is a roll of the dice.&lt;/p&gt;

&lt;p&gt;The hard version of this principle is enforcing consent at the API level — not as a best-practice reminder in the docs, but as a physical gate. The sender calls a consent endpoint, and the system delivers a short, high-reputation consent email to the recipient with approve and reject buttons. The link is signed and cannot be forged. Until the recipient clicks approve, any custom send attempt to that address is discarded — not bounced, not deferred. Because every recipient is consented, complaint rates stay low by construction.&lt;/p&gt;

&lt;p&gt;If you are sending only OTPs and receipts, this section feels inapplicable. It mostly is. Transactional templates — MFA enrollment, OTP codes, order confirmations, new-device alerts — send without the consent step. But the infrastructure-quality argument in Lever 3 still applies to you, and the next section explains why.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lever 2: Continuous engagement monitoring with automatic suppression
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5nsjz44pvu6b5w79hku.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5nsjz44pvu6b5w79hku.png" alt="Illustration of recipient lifecycle stages shown as a timeline with some addresses fading out and others staying bright, representing continuous engagement monitoring and automatic suppression" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Permission at signup is not enough. Recipients disengage over time, change jobs, abandon inboxes. A list that was healthy six months ago is a reputation liability today if you haven't been watching it.&lt;/p&gt;

&lt;p&gt;The fix is continuous monitoring — tracking opens, clicks, bounces, and complaints per recipient, and acting on the data automatically. Three specific behaviors matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Re-permission disengaged recipients before they hurt you.&lt;/strong&gt; An automatic re-permission ping after a period without engagement keeps lists clean. If the recipient doesn't respond, the address drops off the list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Suppress complaints and unsubscribes instantly, workspace-wide.&lt;/strong&gt; When a recipient unsubscribes or marks as spam, the API should physically refuse subsequent sends to that address from any key in the workspace — not later, not after the next list import, immediately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drop hard bounces on the first hit.&lt;/strong&gt; Sending to addresses that no longer exist is one of the strongest negative signals available.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most email APIs surface these metrics in a dashboard. Few enforce them automatically. The difference matters in practice, because a developer who has to manually review engagement data and manually update suppression lists will not do it consistently. Nobody does.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lever 3: Infrastructure that doesn't punish you for other senders' behavior
&lt;/h3&gt;

&lt;p&gt;Even with perfect permission and engagement practices, a sender on a contaminated shared IP pool faces headwinds that have nothing to do with their own behavior. So the infrastructure question is unavoidable: who else is in your IP pool, and what are they doing?&lt;/p&gt;

&lt;p&gt;The alternative to a generic shared pool is a pool where every sender is operating under the same permission-and-engagement constraints — so the aggregate complaint rate stays low by design rather than by luck. When a shared pool is built this way, it is already warm; new senders can send at full volume from day one without a manual warm-up period. At higher volumes, moving to dedicated IP allocation removes the shared-pool variable entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Transactional Email Caveat
&lt;/h2&gt;

&lt;p&gt;If you are reading this and thinking "I only send password resets and OTPs, this doesn't apply to me," part of that is correct and part of it is not.&lt;/p&gt;

&lt;p&gt;Transactional senders often assume they are safe from deliverability problems because their mail is, by definition, wanted. The recipient just asked for a password reset; of course they want the email. That logic is partially true. It is also incomplete.&lt;/p&gt;

&lt;p&gt;Transactional email still lands in spam if the sending IP has poor reputation from other traffic in the same pool. The recipient's intent doesn't matter to the spam filter — the filter never sees it. What the filter sees is the IP, the domain, the authentication result, and the historical pattern. If those signals are bad, your password reset goes to spam even though every recipient genuinely wants it.&lt;/p&gt;

&lt;p&gt;Bounce handling matters here too. Sending OTPs to addresses that no longer exist degrades reputation for the addresses that do. And the moment you add any custom or marketing sends to the same workspace, the reputation of that traffic flows back into your transactional deliverability. Most products start transactional-only and grow into custom sends eventually. Choosing infrastructure that enforces permission on the custom side from day one prevents that growth from quietly degrading the transactional path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Most Email APIs Make This Hard by Design
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F14iyoqntxupnpnrrcz1p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F14iyoqntxupnpnrrcz1p.png" alt="Illustration of interconnected nodes in a shared pool, with some nodes glowing red to represent bad senders affecting the whole group" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is worth asking why permission and engagement tooling is so rare in the developer email market. The answer is structural, not accidental.&lt;/p&gt;

&lt;p&gt;The legacy pricing model — SendGrid Essentials at $19.95/month (up to 100K emails), Pro at $89.95/month for serious 100K usage, $35 at Resend, $75 at Mailgun, around $134 at Postmark for 100,000 emails — is calibrated to a world where the shared pool absorbs the cost of abuse. If a provider's revenue model depends on the volume that includes senders with poor practices, there is limited economic incentive to enforce permission at the API. Doing so would shrink the addressable market and reduce the volume that justifies the price.&lt;/p&gt;

&lt;p&gt;The result is that none of the major developer email providers ship permission verification as a product feature. Mailgun has none. Resend has none. Postmark has none. Mailtrap has none. Amazon SES, at roughly $10–$12 per month for 100,000 emails, is cheaper, but the trade-off is an AWS account, manual IP warm-up, and no permission management of any kind. A developer who wants to implement permission correctly on any of these platforms has to build it themselves — consent tracking, signed approval links, suppression lists, re-permission flows. It is non-trivial engineering work that has nothing to do with the product they are actually trying to ship.&lt;/p&gt;

&lt;p&gt;When permission is enforced at the API level, the economics change. Complaint rates stay low by construction. Sender reputation compounds positively. Abuse-team overhead collapses. The cost structure that justified higher monthly pricing no longer applies.&lt;/p&gt;

&lt;p&gt;This is the structural shift worth paying attention to. The market is the way it is because of how shared pools and shared pricing reinforce each other. Break the loop on either side and the rest of the model becomes optional.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Earned Deliverability Playbook
&lt;/h2&gt;

&lt;p&gt;To compress the argument into something you can act on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Authenticate your domain.&lt;/strong&gt; DKIM, SPF, DMARC. Required, not differentiating. Do it once, correctly, and move on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gate custom sends on explicit consent.&lt;/strong&gt; Do not send marketing or custom email to anyone who has not affirmatively approved it. Enforce this at the API level if you can, not as a manual process you mean to get to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor engagement continuously and suppress automatically.&lt;/strong&gt; Re-permission disengaged recipients before they become liabilities. Suppress complaints and unsubscribes instantly, across every API key in the workspace.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choose infrastructure where the pool is protected by design.&lt;/strong&gt; Your deliverability depends partly on who else is sending from your IP range. That is a choice, not a fixed cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat transactional email as a deliverability asset, not a given.&lt;/strong&gt; OTPs and receipts land in spam too if the infrastructure around them is contaminated.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Deliverability is not a problem you solve. It is a reputation you build — through permission, engagement, and infrastructure that compounds both. The largest senders in the world have known this for years; the playbook is not new. What is new is that it can be automated.&lt;/p&gt;

&lt;p&gt;Earned deliverability, automated. GoodSender was built to handle exactly this — the permission, engagement, and infrastructure discipline described above, enforced by design so you don't have to build it yourself.&lt;/p&gt;

</description>
      <category>deliverability</category>
      <category>dkim</category>
      <category>spf</category>
      <category>dmarc</category>
    </item>
    <item>
      <title>Cold Email's Math Broke in 2026. Here's What Replaces It.</title>
      <dc:creator>Givi Pataridze</dc:creator>
      <pubDate>Tue, 26 May 2026 17:49:10 +0000</pubDate>
      <link>https://dev.to/goodsender/the-more-effective-way-to-replace-cold-email-10c8</link>
      <guid>https://dev.to/goodsender/the-more-effective-way-to-replace-cold-email-10c8</guid>
      <description>&lt;p&gt;Cold email has always made a simple promise: buy a list of contacts, set up an automated sequence, and new sales conversations start landing — cheaply and at scale. For a long time the math more or less held. In 2026 it doesn't, and the reason isn't your copy or your sending tool. It's that the inbox has quietly changed the rules, and cold email is now playing a much harder game, with much less room for error.&lt;/p&gt;

&lt;p&gt;If you're a founder weighing how to spend the next quarter of outreach budget, this is worth understanding before you commit to another sequence.&lt;/p&gt;

&lt;p&gt;The short answer, before the why: the more effective replacement for cold email is &lt;strong&gt;permission-based sending&lt;/strong&gt; — reaching a smaller list of people who opted in and stay engaged, because that's exactly what the 2026 inbox rewards.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8ocklnc99vb33xe3idj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8ocklnc99vb33xe3idj.png" alt="Cold email versus permission-based sending shown as two side-by-side funnels: a cold list leads to complaints, eroding reputation, and the spam folder, while a permission-based list leads to high engagement, earned reputation, and the inbox." width="800" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cold outreach and permission-based sending chase the same goal — but the 2026 inbox rewards only one of them.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually changed
&lt;/h2&gt;

&lt;p&gt;Starting in 2024, Gmail and Yahoo began enforcing real requirements on bulk senders — for Gmail, anyone sending 5,000 or more messages per day to personal Gmail accounts, a classification that becomes permanent once you cross it. Microsoft joined them in May 2025. The headline rules are authentication (SPF, DKIM, DMARC) and one-click unsubscribe, but the one that quietly changes the math for cold email is the spam-complaint threshold. Google's own guidance is to keep your complaint rate below 0.1% and never let it reach 0.3%; at 0.3% or higher, bulk senders lose access to Gmail's mitigation support and take an even stronger hit to inbox delivery, and non-compliant mail can be rejected or sent to spam outright.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkitwrp6cp9rf7qw6f2ja.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkitwrp6cp9rf7qw6f2ja.png" alt="A horizontal gauge of Gmail's spam-complaint thresholds: a green safe zone up to 0.1 percent, an amber zone where delivery suffers between 0.1 and 0.3 percent, and a red zone at 0.3 percent and above where Gmail pulls mitigation support." width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google asks bulk senders to stay under 0.1% spam complaints and treats 0.3% as the danger line.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To put that in human terms: at just one complaint per 1,000 emails you're already past the 0.1% Google wants you under, and at three per 1,000 you've hit the 0.3% line where Gmail pulls its mitigation support. Cold lists are structurally more likely to approach that line, because the recipients never explicitly asked to hear from you. Some of them will be annoyed, and a small fraction of annoyed people is all it takes.&lt;/p&gt;

&lt;p&gt;Here's the part most teams discover too late. The damage isn't always contained to the campaign. Mailbox providers attach reputation to your sending domain and IP and weigh it on signals like complaints, bounces, engagement patterns, authentication, sending consistency, and list quality. A cold campaign that generates complaints doesn't just underperform; it can weaken the reputation signals attached to the domain, subdomain, or infrastructure you send from. If your promotional and transactional mail aren't separated properly, that risk can spill over into messages you actually need people to receive: password resets, receipts, onboarding emails, and real customer replies. The cheap channel turns out to carry one of the most expensive failure modes there is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real problem is permission, not tactics
&lt;/h2&gt;

&lt;p&gt;The instinct is to respond with better tactics: warm-up tools, more inboxes to rotate through, sharper subject lines, AI-written personalization. The harder problem is who you're up against. Mailbox providers read signals across billions of messages and keep getting better at spotting mail people didn't ask for, so tactical workarounds tend to have a short shelf life — and the usual cost of leaning on them is burned sending domains.&lt;/p&gt;

&lt;p&gt;The more useful move is to notice what the largest, most sophisticated senders in the world actually do. They don't lean on cold email. They build permission and engagement into the system from the start, because that's what the inbox most consistently rewards. Permission gets you through the door; sustained engagement keeps it open. Everything else is a workaround for not having those two things.&lt;/p&gt;

&lt;p&gt;That reframes the question. The goal was never "how do I send more cold email without getting caught." It's "how do I build a list of people who actually want to hear from me, as efficiently as cold email promised to be." That list is the asset. It converts better, it complains far less, and it protects the deliverability of your whole domain instead of eroding it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the replacement looks like in practice
&lt;/h2&gt;

&lt;p&gt;A permission-first outreach motion has three moving parts, and none of them are exotic.&lt;/p&gt;

&lt;p&gt;First, you ask before you send. Instead of dropping a pitch into a stranger's inbox, you send a single lightweight message that lets them opt in — one clean ask, with a clear yes. The people who say yes are now reachable; the people who ignore it never enter your promotional sending stream, so they can't complain about a follow-up sequence they never agreed to receive.&lt;/p&gt;

&lt;p&gt;Second, you watch engagement and act on it. People who stop opening and clicking get re-confirmed or quietly dropped, so your active list stays genuinely active. A list that's continuously pruned toward active, consented recipients is how serious senders stay closer to the sub-0.1% complaint rates providers want to see.&lt;/p&gt;

&lt;p&gt;Third, you suppress complaints and unsubscribes instantly and permanently. The moment someone opts out, they're gone from every future send — no accidental re-contact, which is one of the fastest ways to torch a reputation.&lt;/p&gt;

&lt;p&gt;The obvious objection is, "but that gives me a much smaller list." Yes. And that's the point, not the cost. A smaller list of consented, engaged recipients beats a bloated cold list on every metric that actually matters: inbox placement, reply rate, conversion, and the long-term health of your domain. Ten thousand cold contacts that land you in spam are worth less than five hundred people who chose to hear from you. Cold email optimizes for the size of the send. The inbox optimizes for whether anyone wanted it. Build for the second one.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we built this into GoodSender
&lt;/h2&gt;

&lt;p&gt;This is the bet GoodSender is built on, so I'll be upfront that I'm describing our own product here. We took the permission-and-engagement playbook the biggest senders use and made it automatic, because expecting every small team to operate it by hand is unrealistic.&lt;/p&gt;

&lt;p&gt;In practice that means two things run for you. The Permission Loop governs your custom marketing sends: GoodSender emails each recipient a short, high-reputation consent message with approve and reject buttons. An approval unlocks them so your sends go through; if they never approve, the message is simply never sent — so you physically cannot blast marketing mail at people who didn't agree. Transactional template emails — OTP codes, receipts, password resets, MFA prompts — sit outside the loop and send without a consent step, so the messages people are actively waiting for never get held up. The Engagement Check then tracks opens, clicks, bounces, and complaints continuously, re-confirms anyone who's gone quiet for six months, and suppresses unsubscribes and complaints across your whole workspace the instant they happen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Finfezy495zzjwcoqm72e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Finfezy495zzjwcoqm72e.png" alt="Diagram of the Permission Loop in two lanes: transactional templates send straight to the inbox with no consent step, while a marketing email triggers a signed consent email — on approval the recipient is unlocked for all future marketing sends, and on ignore or reject the marketing send is held back. An Engagement Check band monitors permitted recipients over time." width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Permission Loop gates only marketing email — transactional templates send without consent. An approval unlocks the recipient for every future marketing send, and the Engagement Check keeps the list healthy over time.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Because promotional sends are consent-gated and transactional sends are separated by purpose, complaint risk is reduced by design — which is also why we can offer the first 100,000 emails a month free and $1 per 100K after that. The economics only work when the list is clean, so the model rewards exactly the behavior the inbox already rewards.&lt;/p&gt;

&lt;p&gt;None of this is a way to do cold email more sneakily. It's the opposite: a way to stop needing cold email at all, by making the permission-based alternative as fast and low-effort as the thing it replaces. If you've been feeling cold-email returns shrink quarter over quarter, that pressure isn't going to ease. The teams that move to earned, permission-based sending now are the ones most likely to still be landing in the inbox a year from now.&lt;/p&gt;

&lt;p&gt;That's the whole idea behind what we're building. If it resonates, I'd love for you to give it a look — and tell me where I'm wrong.&lt;/p&gt;

</description>
      <category>coldemail</category>
      <category>permissionloop</category>
      <category>deliverability</category>
      <category>engagement</category>
    </item>
    <item>
      <title>How consent-gated email works (and why it's free)</title>
      <dc:creator>Givi Pataridze</dc:creator>
      <pubDate>Thu, 21 May 2026 17:07:31 +0000</pubDate>
      <link>https://dev.to/goodsender/how-consent-gated-email-works-and-why-its-free-5dg8</link>
      <guid>https://dev.to/goodsender/how-consent-gated-email-works-and-why-its-free-5dg8</guid>
      <description>&lt;p&gt;Email infrastructure pricing has barely moved in a decade. Mailgun, Postmark, SendGrid, Resend, all per-email, all clustered in a narrow band. The reason isn't bandwidth, and it isn't storage. It's abuse. Most of what an ESP charges you covers the cost of fighting the senders who shouldn't be on the platform in the first place.&lt;/p&gt;

&lt;p&gt;Remove the abuse, and the price collapses.&lt;/p&gt;

&lt;p&gt;That's the idea behind GoodSender's Permission Loop. Here's how it works, and why the economics finally let us run the first 100,000 emails a month at $0 and keep the curve flat after that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shared-pool problem
&lt;/h2&gt;

&lt;p&gt;Every sender on a typical ESP sits in an IP reputation pool with everyone else on that tier. One bad actor blasts a purchased list, mailbox providers throttle the IPs, and your perfectly legitimate transactional mail starts landing in spam. You did nothing wrong. You're paying for the worst sender on your tier.&lt;/p&gt;

&lt;p&gt;ESPs aren't oblivious to this. They staff anti-abuse teams, run heuristics, freeze accounts, review manually. That work is expensive. Per-email pricing is, in large part, a tax on the entire customer base to cover the cost of policing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Permission Loop
&lt;/h2&gt;

&lt;p&gt;GoodSender flips the order. Before you can send to a recipient, that recipient has to confirm they want your mail. The flow is simple.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You call &lt;code&gt;POST /v1/emails/consent&lt;/code&gt; with the recipient's address.&lt;/li&gt;
&lt;li&gt;We send a short, high-reputation consent email with approve and reject buttons. The link is signed, so the sender can't forge it.&lt;/li&gt;
&lt;li&gt;Once the recipient clicks approve, that address is unlocked across your workspace. Sends go through instantly, from any API key in the workspace.&lt;/li&gt;
&lt;li&gt;If they click reject, the address is suppressed. The original consent email stays live, so they can change their mind later and lift the suppression themselves.&lt;/li&gt;
&lt;li&gt;If they never click, every send to that address is discarded inside GoodSender. Approve is a hard gate, enforced at the API.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Transactional templates (MFA Enrollment, New Device, Login, Order Completed, OTP Code) bypass the gate, because they're already implicitly requested by the recipient's own action. Transactional sends don't change consent state. They only fail if the recipient has explicitly clicked reject.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Engagement Check keeps permission honest
&lt;/h2&gt;

&lt;p&gt;A permission granted today isn't permission granted forever. We track opens, clicks, bounces, and complaints per recipient, aggregated into a live engagement score. Six months without engagement triggers an automatic re-permission ping. No response, the recipient drops off.&lt;/p&gt;

&lt;p&gt;Unsubscribes and spam complaints are suppressed instantly across the entire workspace. No API key in that workspace can mail those addresses again, regardless of which engineer or which integration tries.&lt;/p&gt;

&lt;p&gt;Permission is a snapshot. Engagement is the proof it's still real.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this lets us be free at the volumes most senders need
&lt;/h2&gt;

&lt;p&gt;Permission-gated mail, by construction, has almost no abuse surface.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Purchased lists don't work, because the recipients haven't opted in to &lt;em&gt;your&lt;/em&gt; sending domain.&lt;/li&gt;
&lt;li&gt;Cold sequences don't work, because you can't email someone who hasn't confirmed.&lt;/li&gt;
&lt;li&gt;There's no long-tail decay, because dormant recipients get pruned.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If abuse is structurally prevented, anti-abuse cost trends toward zero. Deliverability stays high without a fire-fighting team. The IP pool runs at unusually low complaint rates by design, and the marginal cost of a sent email, on infrastructure already serving the world's largest senders via Laneful, drops to roughly the cost of running the pipe.&lt;/p&gt;

&lt;p&gt;That's why the first 100,000 emails a month, including consent requests, transactional templates, and marketing sends to consented recipients, cost $0. One bucket, no per-type splits, no tiered accounting. Beyond 100K it's $1 per additional 100,000. No subscriptions, no tiers, no credit card to start. The curve stays flat: roughly $9 a month at one million emails, $99 a month at ten million.&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;100,000 emails a month is about 3,300 sends a day, more than most SaaS apps and small or mid-sized businesses ever reach. For the majority of senders, the bill stays at $0 forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this changes for senders
&lt;/h2&gt;

&lt;p&gt;For indie developers, solo founders, and AI startups building agentic workflows, the time you used to spend on IP warmup, suppression lists, and deliverability tickets becomes a config call. Domain verification takes about five minutes. DKIM, SPF, and DMARC get configured automatically.&lt;/p&gt;

&lt;p&gt;This isn't built for marketing teams running mass-broadcast campaigns. It isn't built for cold-outreach teams. It's built for makers and builders who want every recipient to be someone who actually asked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who this is for
&lt;/h2&gt;

&lt;p&gt;The Permission Loop isn't a feature you can A/B test against an open rate. It's a constraint. It rules out workflows that other ESPs accommodate — purchased lists, cold sequences, lapsed-subscriber reactivation campaigns — and it rules them out at the API, not in the terms of service.&lt;/p&gt;

&lt;p&gt;If your sending depends on those workflows, we're not the right tool, and we'll save you time by saying so now. If your sending is mostly transactional plus a newsletter people actually signed up for, the constraint is invisible and the bill is $0.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Pricing as of April 2026.&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>permissionloop</category>
      <category>consent</category>
      <category>pricing</category>
      <category>deliverability</category>
    </item>
    <item>
      <title>Per-email pricing is a tax on bad senders. You're paying it.</title>
      <dc:creator>Givi Pataridze</dc:creator>
      <pubDate>Wed, 20 May 2026 19:08:55 +0000</pubDate>
      <link>https://dev.to/goodsender/per-email-pricing-is-a-tax-on-bad-senders-youre-paying-it-1ech</link>
      <guid>https://dev.to/goodsender/per-email-pricing-is-a-tax-on-bad-senders-youre-paying-it-1ech</guid>
      <description>&lt;p&gt;Open your last Mailgun invoice. The line says &lt;em&gt;per email&lt;/em&gt;. It isn't.&lt;/p&gt;

&lt;p&gt;A real email, the SMTP handshake, the DKIM signing, the bytes on the wire, costs a fraction of a fraction of a cent in 2026. AWS will rent you SES at roughly $0.10 per thousand. The marginal cost of a sent message has been rounding-error money for years.&lt;/p&gt;

&lt;p&gt;So what are you paying for?&lt;/p&gt;

&lt;p&gt;You're paying for the abuse team.&lt;/p&gt;

&lt;h2&gt;
  
  
  The line item nobody itemizes
&lt;/h2&gt;

&lt;p&gt;Every general-purpose ESP runs an anti-abuse organization. Heuristic detection on outbound traffic. Manual review queues for new accounts. Suppression-list infrastructure. Relationships with mailbox providers and feedback loops with Gmail, Outlook, Yahoo. Lawyers responding to subpoenas. On-call engineers who page when an IP gets blocklisted at 3 a.m. because somebody else on the same shared pool decided to test a list they bought somewhere on the internet.&lt;/p&gt;

&lt;p&gt;That work is real and necessary. It's also expensive, and it has to be paid for somehow. The way it gets paid for is the per-email price.&lt;/p&gt;

&lt;p&gt;A useful exercise: line up the public list prices for 100,000 emails a month.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mailgun: $75&lt;/li&gt;
&lt;li&gt;Postmark: roughly $134&lt;/li&gt;
&lt;li&gt;SendGrid: $34.95 (no free plan since May 2025)&lt;/li&gt;
&lt;li&gt;Resend: $35, climbing to roughly $650 at one million emails&lt;/li&gt;
&lt;li&gt;Amazon SES: roughly $10–12, if you bring your own AWS account, warm-up, and compliance posture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The infrastructure cost is roughly the same. The variance isn't bandwidth — it's how much abuse defense each platform absorbs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The senders who pay the most
&lt;/h2&gt;

&lt;p&gt;Here's the part that usually goes unsaid. Clean senders subsidize dirty ones.&lt;/p&gt;

&lt;p&gt;If you run a SaaS app sending password resets and receipts, your complaint rate is probably under 0.01%. You generate roughly zero load on the abuse team. And yet you're paying the same per-message rate as the customer next door who's blasting a list they "warmed up" by importing it from a bankrupt LinkedIn scraper.&lt;/p&gt;

&lt;p&gt;The pricing isn't malicious. It's structural. Shared infrastructure means shared cost. The platforms are doing the right thing operationally, pooling abuse defense across their customer base. But pooled costs are pooled by design. You can't pay less just because you behave better, because the platform has no mechanism to &lt;em&gt;know&lt;/em&gt; you behave better until well after the bill has been printed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remove the abuse, remove the cost
&lt;/h2&gt;

&lt;p&gt;The way out isn't a discount code. It's a different model. GoodSender's Permission Loop requires recipients to confirm before a sender can mail them, which means purchased lists and cold sequences don't function and the abuse surface is structurally near-zero.&lt;/p&gt;

&lt;p&gt;Once that's true, the math changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No abuse team rotation to staff.&lt;/li&gt;
&lt;li&gt;No suppression infrastructure to scale.&lt;/li&gt;
&lt;li&gt;No cross-customer reputation contamination to clean up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The marginal cost of an email drops back to what it actually is — pipe, plus a little metadata. That's why the first 100,000 emails a month cost $0, and why the curve stays flat at scale: roughly $9 a month at one million, $99 at ten million.&lt;sup id="fnref1"&gt;1&lt;/sup&gt; The model still doesn't tax you for someone else's behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to look at when you compare
&lt;/h2&gt;

&lt;p&gt;If you're evaluating email APIs in 2026, don't compare per-email price first. Compare &lt;em&gt;what's in the price&lt;/em&gt; — whether your reputation is pooled with the worst sender on your tier, whether the platform prevents abuse structurally or polices it with a team, and whether your per-email cost will track infrastructure or anti-abuse overhead as you scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bet
&lt;/h2&gt;

&lt;p&gt;Per-email pricing has held its shape for fifteen years because nobody had a structural reason to break it. The shared-pool model required pooled cost, pooled cost required per-message billing, and the abuse tax stayed embedded in the rate.&lt;/p&gt;

&lt;p&gt;That's the part we think breaks next. Not because senders demanded it — they've been paying the tax without complaining for a long time — but because the model that makes the tax unnecessary is finally cheaper to run than the model that requires it.&lt;/p&gt;

&lt;p&gt;Whether GoodSender is the platform that proves the point or somebody else is, the per-email rate as a category is on borrowed time.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Pricing current as of April 2026.&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>email</category>
      <category>deliverability</category>
      <category>api</category>
      <category>saas</category>
    </item>
  </channel>
</rss>
