Email Marketing That Avoids Spam

You wrote a solid newsletter, sent it to 3,000 subscribers, and the open rate came back in the single digits. A quick check shows most of it landed in spam or the Promotions tab. T...

Email Marketing That Avoids Spam

You wrote a solid newsletter, sent it to 3,000 subscribers, and the open rate came back in the single digits. A quick check shows most of it landed in spam or the Promotions tab. The cause is usually not your copy. It is the technical setup and sender reputation that nobody has looked after.

Since February 2024, Gmail and Yahoo have enforced stricter rules for bulk senders: authenticated domains, one-click unsubscribe, and low spam complaint rates. This guide covers the concrete steps that get your email into the inbox, including DNS records and a code example for developers sending from their own application.

How Mailbox Providers Decide: Inbox or Spam

Gmail, Outlook, and Yahoo evaluate each message on several layers at once:

  1. Identity: is the email really from the domain owner? Checked with SPF, DKIM, and DMARC.
  2. Reputation: what is the sending history of the domain and IP? High bounces, complaints, or sudden volume spikes hurt it.
  3. Engagement and content: do recipients open, reply, and move messages to the inbox, or delete and report them? Content resembling phishing raises flags too.

Content matters, but the first two layers usually decide the outcome. An ordinary email with good authentication and reputation reaches the inbox; a beautifully written one from an unauthenticated domain often does not.

Step 1: Authenticate Your Domain

RecordWhat it doesCommon mistake
SPFLists the servers allowed to send mail for your domainPublishing two separate SPF records instead of merging them into one
DKIMAdds a cryptographic signature proving the message was not alteredAdding the DNS record but never enabling signing in the sending service
DMARCTells receivers what to do when SPF/DKIM fail, and sends you reportsJumping straight to p=reject before reading any reports

Example records for a domain using Google Workspace for staff mail and a bulk provider such as Mailgun or SendGrid for campaigns:

; SPF (exactly one TXT record at the root)
yourstore.com.  TXT  "v=spf1 include:_spf.google.com include:mailgun.org ~all"

; DKIM (selector and key are provided by your sending service)
mx._domainkey.yourstore.com.  TXT  "k=rsa; p=MIGfMA0GCSqGSIb3DQEB..."

; DMARC (start in monitoring mode)
_dmarc.yourstore.com.  TXT  "v=DMARC1; p=none; rua=mailto:dmarc@yourstore.com; adkim=r; aspf=r"

Run DMARC at p=none for two to four weeks and read the aggregate reports (free tools like Postmark's DMARC digests or dmarcian make them readable). Once every legitimate source passes, move to p=quarantine and eventually p=reject. Use MXToolbox or Gmail's "Show original" view to confirm each check says PASS.

Use a subdomain for marketing

Send newsletters from something like news.yourstore.com and keep transactional mail (receipts, password resets) on the main domain or a separate subdomain. If campaign reputation dips, critical messages are not dragged down with it.

Step 2: Support One-Click Unsubscribe

Bulk senders must include a List-Unsubscribe header that supports one-click unsubscribe (RFC 8058) in addition to a visible link. If you send campaigns from a Laravel app, add the headers in your Mailable:

use Illuminate\Mail\Mailables\Headers;
use Illuminate\Support\Facades\URL;

public function headers(): Headers
{
    $url = URL::signedRoute('newsletter.unsubscribe', [
        'subscriber' => $this->subscriber->id,
    ]);

    return new Headers(text: [
        'List-Unsubscribe'      => '<' . $url . '>',
        'List-Unsubscribe-Post' => 'List-Unsubscribe=One-Click',
    ]);
}

The unsubscribe route must accept a POST without login or a CSRF token, because the request comes from the mailbox provider, not the user's browser. In Laravel 11, exclude it via validateCsrfTokens(except: [...]) in bootstrap/app.php and protect it with the signed middleware. More on that mindset in Web Application Security: 10 Must-Have Best Practices.

Step 3: Keep Your List Clean

Purchased or scraped lists are the fastest way to wreck a sender reputation: dead addresses, spam traps, and people who never asked to hear from you.

  • Use double opt-in to filter typos and bots.
  • Suppress hard bounces immediately.
  • Apply a sunset policy: subscribers with no opens or clicks in 90 to 180 days get one re-permission email, then are removed if they stay silent.
  • Keep spam complaints below Gmail's 0.3% ceiling, ideally well under 0.1%. Monitor them in Google Postmaster Tools and Microsoft SNDS.

Developers should store subscriber state explicitly, with columns like confirmed_at, last_engaged_at, bounced_at, and unsubscribed_at, and update them from your provider's bounce and complaint webhooks. Process those webhooks on a queue, as covered in Laravel Queues and Jobs for Heavy Tasks.

Step 4: Warm Up New Domains Gradually

A new domain that suddenly sends 20,000 messages looks like a spammer. Ramp up, starting with your most engaged subscribers. An illustrative schedule:

  1. Week 1: 200 to 500 emails per day to people who opened in the last 30 days.
  2. Week 2: around 1,000 to 2,000 per day if bounces and complaints stay low.
  3. Weeks 3 and 4: keep doubling until the whole list is covered.
  4. If complaints rise, cut volume and find the segment causing them.

Step 5: Write Content That Does Not Look Suspicious

  • Avoid all-caps subject lines and strings of exclamation marks.
  • Do not send a single large image with no text.
  • Avoid public URL shorteners and link domains unrelated to your sending domain.
  • Keep a consistent sender name, such as "Maya at Your Store".
  • Include your physical business address and a visible unsubscribe link, as required by laws like CAN-SPAM and GDPR-related rules.
  • Ship a plain-text version alongside HTML.

Pre-Send Checklist

  • SPF, DKIM, and DMARC all show PASS on a test message.
  • List-Unsubscribe header and in-body link both work.
  • Hard bounces and subscribers inactive for 180+ days are suppressed.
  • Subject line is honest and matches the content.
  • Balanced text and images, with alt text on every image.
  • Test sends checked in Gmail, Outlook, and Yahoo accounts.
  • Volume is not dramatically higher than your previous send.

Choosing How to Send

Small businesses are usually best served by Mailchimp, MailerLite, Brevo, or Kit, which handle bounces, compliance pages, and suppression lists for you. Developers building email into their own product typically use Amazon SES, Postmark, Mailgun, or Resend through Laravel's mail drivers. Avoid sending bulk email through shared hosting SMTP: limits are low and the IP reputation is shared with strangers, a point also made in Deploying a Laravel App to Shared Hosting.

Deliverability is ongoing maintenance, not a one-time setting. Review Postmaster data monthly, read your DMARC reports, and prune your list on a schedule, and your messages will keep reaching the people who actually want them.

Yudhi
Written by
Yudhi
Founder & Lead Developer, GudangCode

Yudhi is the founder of GudangCode and a Laravel developer who has built dozens of ready-to-use business information systems — from POS and HRIS to management apps. He writes guides and articles on GudangCode to help Indonesian developers run, understand, and deploy Laravel source code correctly.

LaravelPHPMySQLSistem Informasi Bisnis See all articles by Yudhi
Want the full source code & apps?

Sign up free to download ready-to-use business applications, information systems, and Laravel source code.

Sign Up Free & Download
Email Marketing Spam Marketing & SEO
Share this article
Back to Blog
📚 Free Learning Hub

Learn Coding for Free at DhieCoderWeb

Explore Laravel, PHP, JavaScript tutorials, source code, web development guides, and practical programming tips.

DhieCoderWeb
100+
Tutorials
Free
Learning
SEO
Tips
Visit Dhiecoderweb.com →

Get Full Access Now!

Join our membership and unlock exclusive access to all premium features. Fast, easy, and ready to use instantly.

Join Membership Now
Tim Support
Online
Isi data dulu untuk mulai chat:
Beri rating & testimoni sebelum menutup:
Live chat by gudangcode.com