<?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: Dev May Cry</title>
    <description>The latest articles on DEV Community by Dev May Cry (@devmaycry).</description>
    <link>https://dev.to/devmaycry</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%2F3779650%2F5a6059f6-3f0e-459f-8994-09f111ba27e3.png</url>
      <title>DEV Community: Dev May Cry</title>
      <link>https://dev.to/devmaycry</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/devmaycry"/>
    <language>en</language>
    <item>
      <title>Anyone can write “From: bank.com” in an email. Here’s how Gmail catches the fake.</title>
      <dc:creator>Dev May Cry</dc:creator>
      <pubDate>Fri, 30 Oct 2026 16:15:47 +0000</pubDate>
      <link>https://dev.to/devmaycry/anyone-can-write-from-bankcom-in-an-email-heres-how-gmail-catches-the-fake-27ee</link>
      <guid>https://dev.to/devmaycry/anyone-can-write-from-bankcom-in-an-email-heres-how-gmail-catches-the-fake-27ee</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; SMTP was born in 1982 with no sender check. Today Gmail runs 3 checks before an email reaches your inbox: SPF, DKIM and DMARC. SPF and DKIM alone are not enough. DMARC is what stops the scam.&lt;/p&gt;

&lt;p&gt;Let's follow one fake email from "bank.com" to João, step by step.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Every email has two senders
&lt;/h2&gt;

&lt;p&gt;Think of a real letter. The envelope is what the mail carrier reads. The letter inside has the "From:" that you read. Email works the same way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;MAIL FROM:&lt;/code&gt; (the envelope) is only read by servers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;From:&lt;/code&gt; (the letter) is what you see in your inbox&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A scammer can put a different name in each one.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. SPF (Sender Policy Framework): who is allowed to send?
&lt;/h2&gt;

&lt;p&gt;It's a list in DNS with the servers that can send email for a domain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ dig TXT bank.com
v=spf1 include:amazonses.com -all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The scammer's server is not on the list, so SPF fails. Note: SPF only checks the &lt;strong&gt;envelope&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. DKIM (DomainKeys Identified Mail): was the email signed?
&lt;/h2&gt;

&lt;p&gt;The sending server signs the email with a private key. Gmail gets the public key from DNS and checks the signature. If anyone changes the text, the signature breaks. The &lt;code&gt;d=&lt;/code&gt; tag shows &lt;strong&gt;who&lt;/strong&gt; signed it.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The trick: the scammer uses his own domain
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight email"&gt;&lt;code&gt;&lt;span class="nt"&gt;MAIL FROM&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="na"&gt;&amp;lt;x@scam.com&amp;gt;   spf=pass  (scam.com)&lt;/span&gt;
&lt;span class="nt"&gt;DKIM d=scam.com          dkim=pass (scam.com)
From&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="na"&gt; support@bank.com   &amp;lt;- João sees this&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both checks pass, but for the wrong domain.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. DMARC: do the names match?
&lt;/h2&gt;

&lt;p&gt;DMARC = Domain-based Message Authentication, Reporting and Conformance.&lt;/p&gt;

&lt;p&gt;It asks whether the domain in &lt;code&gt;From:&lt;/code&gt; is the same domain that passed SPF or DKIM. This is called &lt;strong&gt;alignment&lt;/strong&gt;. Here scam.com ≠ bank.com, so DMARC fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. The domain owner decides what happens
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_dmarc.bank.com  TXT  "v=DMARC1; p=reject"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;p=none&lt;/code&gt; → only watch&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;p=quarantine&lt;/code&gt; → send to spam&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;p=reject&lt;/code&gt; → refuse the email&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The bank also gets reports about who is trying to use its name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Without DMARC
&lt;/h2&gt;

&lt;p&gt;Gmail has no rule to apply, and the fake email can land in João's inbox. That's why Gmail and Yahoo have required DMARC since 2024 for anyone who sends more than 5,000 emails per day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test your domain
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dig TXT _dmarc.yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sources: RFC 7208 (SPF), RFC 6376 (DKIM), RFC 7489 (DMARC)&lt;/p&gt;

&lt;p&gt;Does your domain already have DMARC? &lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>networking</category>
      <category>security</category>
    </item>
    <item>
      <title>send() returned true. The email never arrived. Following one email from your app to the inbox</title>
      <dc:creator>Dev May Cry</dc:creator>
      <pubDate>Thu, 29 Oct 2026 17:09:47 +0000</pubDate>
      <link>https://dev.to/devmaycry/send-returned-true-the-email-never-arrived-following-one-email-from-your-app-to-the-inbox-3j2a</link>
      <guid>https://dev.to/devmaycry/send-returned-true-the-email-never-arrived-following-one-email-from-your-app-to-the-inbox-3j2a</guid>
      <description>&lt;p&gt;Most apps treat send() === true as “delivered”. It isn’t. It only means your email provider accepted the message. The real trip starts after that, and that’s where most failures happen.&lt;/p&gt;

&lt;p&gt;I followed one email through the whole route: a sign-up confirmation with a typo in the address.&lt;/p&gt;

&lt;p&gt;The route&lt;/p&gt;

&lt;p&gt;Stop 1 · App → provider (port 587): your app logs in, starts TLS and submits the message. send() returns true here.&lt;br&gt;
Stop 2 · DNS: the provider’s MTA looks up the MX record of gmail.com to find which server receives mail for that domain.&lt;br&gt;
Stop 3 · The SMTP conversation (port 25): EHLO, MAIL FROM, RCPT TO, DATA. The envelope decides delivery, not the To: header you see.&lt;br&gt;
Stop 4 · The response code: 2xx accepted · 4xx temporary (defer and retry with backoff) · 5xx permanent (bounce, don’t retry).&lt;/p&gt;

&lt;p&gt;What happened to our email&lt;br&gt;
RCPT TO:&lt;a href="mailto:joao.silvaa@gmail.com"&gt;joao.silvaa@gmail.com&lt;/a&gt; → 550 5.1.1 user unknown.&lt;br&gt;
The provider records a bounce and suppresses the address. Your app still thinks everything worked, unless it listens to bounce notifications (webhooks, SNS, etc.).&lt;/p&gt;

&lt;p&gt;Takeaways&lt;/p&gt;

&lt;p&gt;“Accepted” and “delivered” are different states. Store them separately.&lt;br&gt;
Keep delivery events per message: delivered, deferred, bounced.&lt;br&gt;
Never retry a 5xx. Retry a 4xx with backoff. RFC 5321 suggests at least 30 minutes between retries and giving up after 4–5 days.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>softwareengineering</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Dual write: the bug hiding between your database and your message broker</title>
      <dc:creator>Dev May Cry</dc:creator>
      <pubDate>Thu, 29 Oct 2026 12:01:51 +0000</pubDate>
      <link>https://dev.to/devmaycry/dual-write-the-bug-hiding-between-your-database-and-your-message-broker-3mlg</link>
      <guid>https://dev.to/devmaycry/dual-write-the-bug-hiding-between-your-database-and-your-message-broker-3mlg</guid>
      <description>&lt;p&gt;You save an order to the database and then publish an &lt;code&gt;order.created&lt;/code&gt; event. Two lines of code. What could go wrong?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="no"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nc"&gt;Kafka&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'order.created'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// what if this fails?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a &lt;strong&gt;dual write&lt;/strong&gt;: one operation writing to two different systems (database + broker, database + cache, database + search index) with no transaction covering both.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it breaks:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Partial failure:&lt;/strong&gt; the order is committed, but the publish fails (network blip, broker down, process killed mid-request). The order exists, and no downstream service ever hears about it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swapping the order doesn't help:&lt;/strong&gt; publish first and you can end up with an event for an order that was never saved.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Race conditions:&lt;/strong&gt; two concurrent requests can write in a different order to each system, leaving them out of sync.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It even hides in familiar patterns. Dispatching a queued job with &lt;code&gt;afterCommit()&lt;/code&gt; in Laravel is still a dual write: if the process dies between the commit and the push to Redis, the job is gone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix: Transactional Outbox&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Write the event to an &lt;code&gt;outbox&lt;/code&gt; table &lt;em&gt;inside the same database transaction&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="no"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nc"&gt;OutboxMessage&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="s1"&gt;'topic'&lt;/span&gt;   &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'order.created'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'payload'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toJson&lt;/span&gt;&lt;span class="p"&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;A separate worker reads pending outbox rows, publishes them, and marks them as sent. Now it's atomic: either both the order and the event are saved, or neither is.&lt;/p&gt;

&lt;p&gt;One catch: the relay can publish a message and crash before marking it as sent, so delivery is &lt;strong&gt;at-least-once&lt;/strong&gt;. Your consumers need to be idempotent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Other options:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Change Data Capture (CDC):&lt;/strong&gt; tools like Debezium read the database's transaction log and turn changes into events. The database stays the single source of truth.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event sourcing:&lt;/strong&gt; the event log &lt;em&gt;is&lt;/em&gt; the source of truth, and everything else is a projection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two-phase commit:&lt;/strong&gt; works in theory, but it's heavy, couples your services, and most brokers don't support it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ever been bitten by a dual write in production? How did you handle it?&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>distributedsystems</category>
      <category>eventdriven</category>
      <category>backend</category>
    </item>
    <item>
      <title>Game build with REA</title>
      <dc:creator>Dev May Cry</dc:creator>
      <pubDate>Mon, 26 Oct 2026 19:28:49 +0000</pubDate>
      <link>https://dev.to/devmaycry/game-build-with-rea-4bn9</link>
      <guid>https://dev.to/devmaycry/game-build-with-rea-4bn9</guid>
      <description>&lt;p&gt;An idea I had, my favorite game of all time, and my desire to learn by doing. I used REA to turn this combination into From the Cross to Glory, a pixel art experience inspired by Castlevania: Symphony of the Night. The idea was to use the game mechanics to tell a story: Jesus arrives wounded, with limited movements. After receiving the Father’s message, He takes His glorified form to face Death. It was a great opportunity to learn about sprite adaptation, programming, dialogue, visual effects, and how to create a playable version directly in the browser.&lt;/p&gt;

&lt;p&gt;🎮 Play here: &lt;a href="https://thalles-aguiar.itch.io/da-cruz-a-gloria" rel="noopener noreferrer"&gt;https://thalles-aguiar.itch.io/da-cruz-a-gloria&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The game lasts 5 minutes.&lt;/p&gt;

&lt;p&gt;Fan project developed for learning purposes only, with no commercial goals. Credit goes to Konami for Castlevania: Symphony of the Night and the original characters, graphics, music, and other elements used. This is an unofficial project and is not connected to Konami.&lt;/p&gt;

&lt;h1&gt;
  
  
  REA #GameDev #DesenvolvimentoDeJogos #PixelArt #AprendizadoNaPrática
&lt;/h1&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7yqjnzxxtfg84u944p5f.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7yqjnzxxtfg84u944p5f.png" alt=" " width="800" height="635"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>learning</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
