<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>sharkflood8</title>
    <link>//sharkflood8.bravejournal.net/</link>
    <description></description>
    <pubDate>Mon, 04 May 2026 21:02:40 +0000</pubDate>
    <item>
      <title>The Best Heroku Alternatives in 2025 (For Developers Who Actually Need Control)</title>
      <link>//sharkflood8.bravejournal.net/the-best-heroku-alternatives-in-2025-for-developers-who-actually-need-control</link>
      <description>&lt;![CDATA[Heroku was the platform that taught a generation of developers what &#34;platform as a service&#34; meant. Then Salesforce killed the free tier, repriced everything, and left millions of developers looking for somewhere else to run their apps. If you&#39;re still on Heroku — or evaluating it for the first time — here&#39;s the honest comparison of where your money actually goes better. ## What Heroku Costs Now Heroku&#39;s current pricing is built around dynos — their unit of compute. A basic Eco dyno runs $5/month, but it sleeps after 30 minutes of inactivity, making it unusable for anything production. A Basic dyno that stays awake is $7/month. For a simple production app with a database: - Basic dyno (no sleep): $7/month - Heroku Postgres (Mini, 10k rows): $5/month - Heroku Redis (Mini): $3/month That&#39;s $15/month for a minimal production app before you touch custom domains, SSL certificates, or add-ons. Scale to Standard-1X dynos and you&#39;re at $25/month for compute alone. The Standard-2X tier — what you need for anything with real traffic — is $50/month per dyno. No SSH. No real filesystem. No Docker. fast wordpress hosting, &#39;s the pricing structure. ## Railway Railway is the most developer-friendly Heroku alternative for apps that started on Heroku. The deployment model is nearly identical — connect a GitHub repo, Railway builds and runs it. The pricing model is where it diverges. Railway charges based on actual usage: CPU time, RAM, and bandwidth consumed. For low-traffic applications, this is cheaper than Heroku. For production applications with sustained traffic, the bills become unpredictable. The core issue: Railway&#39;s pricing is hard to reason about before you deploy. A Node.js app that processes background jobs constantly will run you $30-60/month on Railway. A high-traffic Django API that you&#39;d expect to cost $15 ends up at $45 because RAM consumption is measured per-second over the entire billing period. Developers who moved from Heroku to Railway frequently report the first month&#39;s bill being a surprise. Railway also has no SSH access. If your app has a bug you can only diagnose by connecting to the running container, Railway isn&#39;t an option. ## Render Render addressed Heroku&#39;s sleeping free tier by eliminating it — you pay for compute that stays awake. The pricing is more predictable than Railway: a fixed $7/month for a 256MB RAM instance, $25/month for 512MB. The limitation that trips developers up: Render doesn&#39;t support persistent disk on the cheapest tiers. If your application writes to the local filesystem (logs, uploads, temporary files), you&#39;ll need to route everything through object storage (S3-compatible), which adds both complexity and cost. Most applications that worked on Heroku need at least one significant refactor to work cleanly on Render. Cold start latency on Render&#39;s lower tiers is also a known issue. Requests that arrive during a container restart can take 10-30 seconds to resolve. For user-facing applications, this is a bad experience. ## Fly.io Fly.io runs your Docker containers across a global network of edge datacenters, which is genuinely useful for latency-sensitive applications. The architecture is different from traditional PaaS — you manage Fly machines, which are microVMs, through a CLI. The learning curve is steeper than Heroku or Railway. Fly has its own concepts (machines, apps, volumes, private networking) that take time to understand. The \flyctl\ CLI is powerful but the documentation assumes you&#39;re comfortable with infrastructure concepts that Heroku deliberately hid from you. Pricing is usage-based and reasonably transparent. A small app with one machine (1 shared CPU, 256MB RAM) fits within the free allowance. Real production apps run $5-20/month depending on machine specs. The complexity tradeoff: Fly gives you more control than Heroku but requires more operational knowledge. It&#39;s a strong choice if you want global distribution and are willing to learn the tooling. ## DigitalOcean App Platform DigitalOcean&#39;s App Platform is a managed PaaS built on top of their infrastructure. It detects your language, runs builds, and handles deployments. The $5/month Basic tier is limited but functional for personal projects. The Professional tier at $12/month per container is where App Platform becomes viable for production. You get 1 vCPU, 1GB RAM, horizontal scaling, and no sleep. Database add-ons (a managed PostgreSQL database starts at $15/month) push the total cost to $27/month for a real app. App Platform doesn&#39;t support SSH into running containers. Like Heroku, you&#39;re operating blind — you get logs, but you can&#39;t exec into the container to diagnose issues. For most teams this is an acceptable tradeoff; for teams that do regular container-level debugging, it isn&#39;t. ## Self-Managed VPS (Caution) The seemingly obvious move: $6/month DigitalOcean Droplet or Hetzner VPS, install everything yourself, enjoy the savings. This works if you enjoy server administration. It does not work if you want to spend your time on your application. Self-managed VPS responsibilities: - OS security patches (and rebooting after kernel updates) - SSL certificate issuance and renewal via certbot - Reverse proxy configuration (Nginx or Caddy) - Process management (systemd or PM2 or Supervisor) - Log rotation - Backup configuration - Monitoring setup - Database installation and tuning Each of these is a rabbit hole. Combined, they&#39;re a part-time job. The $6/month Droplet has a hidden cost measured in engineering hours. ## What to Actually Look For in a Heroku Alternative After evaluating all the options, the features that matter for production apps: \\Persistent containers\\ — no sleeping, no cold starts. Your app responds instantly when a request arrives. \\SSH / exec access\\ — the ability to run commands inside a running container is essential for debugging, database migrations that need supervision, and one-off tasks. Any platform that blocks this is making operational work harder than it needs to be. \\Predictable billing\\ — usage-based pricing is not inherently bad, but you need to be able to estimate your monthly cost before deploying. Platforms that express pricing as &#34;per CPU-second&#34; make this impossible without running the app first. \\Co-located databases\\ — your database should run on the same private network as your application. Network latency between app and database is one of the most impactful performance factors, and it&#39;s one most PaaS platforms handle poorly. \\Docker support\\ — if your app runs in Docker locally, it should run in Docker in production. Platforms that force you into language-specific buildpacks add a layer of abstraction that causes subtle production/development divergence. \\Fixed monthly pricing\\ — the best platform for most developers is one where a $X/month plan means exactly $X, not &#34;$X plus whatever your app consumed this month.&#34; ## The Bottom Line Heroku leaving the free tier was disruptive, but the replacements are genuinely better for most use cases. Railway is better for simple apps with variable traffic. Fly.io is better for global distribution. wordpress 99.9 uptime cheap wordpress hosting no cpanel wordpress hosting no renewal hike is better for HTTP services that don&#39;t need filesystem persistence. For developers who want full Docker support, SSH access, co-located databases, and predictable fixed pricing, the answer isn&#39;t any of Heroku&#39;s direct successors — it&#39;s platforms built specifically for container-native deployment with developer experience as the primary design constraint. The era of paying Heroku prices for Heroku limitations is over. The alternatives have caught up.]]&gt;</description>
      <content:encoded><![CDATA[<p>Heroku was the platform that taught a generation of developers what “platform as a service” meant. Then Salesforce killed the free tier, repriced everything, and left millions of developers looking for somewhere else to run their apps. If you&#39;re still on Heroku — or evaluating it for the first time — here&#39;s the honest comparison of where your money actually goes better. ## What Heroku Costs Now Heroku&#39;s current pricing is built around dynos — their unit of compute. A basic Eco dyno runs $5/month, but it sleeps after 30 minutes of inactivity, making it unusable for anything production. A Basic dyno that stays awake is $7/month. For a simple production app with a database: – Basic dyno (no sleep): $7/month – Heroku Postgres (Mini, 10k rows): $5/month – Heroku Redis (Mini): $3/month That&#39;s $15/month for a minimal production app before you touch custom domains, SSL certificates, or add-ons. Scale to Standard-1X dynos and you&#39;re at $25/month for compute alone. The Standard-2X tier — what you need for anything with real traffic — is $50/month per dyno. No SSH. No real filesystem. No Docker. <a href="https://doc.adminforge.de/s/gpnCdjm6Be">fast wordpress hosting,</a> &#39;s the pricing structure. ## Railway Railway is the most developer-friendly Heroku alternative for apps that started on Heroku. The deployment model is nearly identical — connect a GitHub repo, Railway builds and runs it. The pricing model is where it diverges. Railway charges based on actual usage: CPU time, RAM, and bandwidth consumed. For low-traffic applications, this is cheaper than Heroku. For production applications with sustained traffic, the bills become unpredictable. The core issue: Railway&#39;s pricing is hard to reason about before you deploy. A Node.js app that processes background jobs constantly will run you $30-60/month on Railway. A high-traffic Django API that you&#39;d expect to cost $15 ends up at $45 because RAM consumption is measured per-second over the entire billing period. Developers who moved from Heroku to Railway frequently report the first month&#39;s bill being a surprise. Railway also has no SSH access. If your app has a bug you can only diagnose by connecting to the running container, Railway isn&#39;t an option. ## Render Render addressed Heroku&#39;s sleeping free tier by eliminating it — you pay for compute that stays awake. The pricing is more predictable than Railway: a fixed $7/month for a 256MB RAM instance, $25/month for 512MB. The limitation that trips developers up: Render doesn&#39;t support persistent disk on the cheapest tiers. If your application writes to the local filesystem (logs, uploads, temporary files), you&#39;ll need to route everything through object storage (S3-compatible), which adds both complexity and cost. Most applications that worked on Heroku need at least one significant refactor to work cleanly on Render. Cold start latency on Render&#39;s lower tiers is also a known issue. Requests that arrive during a container restart can take 10-30 seconds to resolve. For user-facing applications, this is a bad experience. ## Fly.io Fly.io runs your Docker containers across a global network of edge datacenters, which is genuinely useful for latency-sensitive applications. The architecture is different from traditional PaaS — you manage Fly machines, which are microVMs, through a CLI. The learning curve is steeper than Heroku or Railway. Fly has its own concepts (machines, apps, volumes, private networking) that take time to understand. The `flyctl` CLI is powerful but the documentation assumes you&#39;re comfortable with infrastructure concepts that Heroku deliberately hid from you. Pricing is usage-based and reasonably transparent. A small app with one machine (1 shared CPU, 256MB RAM) fits within the free allowance. Real production apps run $5-20/month depending on machine specs. The complexity tradeoff: Fly gives you more control than Heroku but requires more operational knowledge. It&#39;s a strong choice if you want global distribution and are willing to learn the tooling. ## DigitalOcean App Platform DigitalOcean&#39;s App Platform is a managed PaaS built on top of their infrastructure. It detects your language, runs builds, and handles deployments. The $5/month Basic tier is limited but functional for personal projects. The Professional tier at $12/month per container is where App Platform becomes viable for production. You get 1 vCPU, 1GB RAM, horizontal scaling, and no sleep. Database add-ons (a managed PostgreSQL database starts at $15/month) push the total cost to $27/month for a real app. App Platform doesn&#39;t support SSH into running containers. Like Heroku, you&#39;re operating blind — you get logs, but you can&#39;t exec into the container to diagnose issues. For most teams this is an acceptable tradeoff; for teams that do regular container-level debugging, it isn&#39;t. ## Self-Managed VPS (Caution) The seemingly obvious move: $6/month DigitalOcean Droplet or Hetzner VPS, install everything yourself, enjoy the savings. This works if you enjoy server administration. It does not work if you want to spend your time on your application. Self-managed VPS responsibilities: – OS security patches (and rebooting after kernel updates) – SSL certificate issuance and renewal via certbot – Reverse proxy configuration (Nginx or Caddy) – Process management (systemd or PM2 or Supervisor) – Log rotation – Backup configuration – Monitoring setup – Database installation and tuning Each of these is a rabbit hole. Combined, they&#39;re a part-time job. The $6/month Droplet has a hidden cost measured in engineering hours. ## What to Actually Look For in a Heroku Alternative After evaluating all the options, the features that matter for production apps: **Persistent containers** — no sleeping, no cold starts. Your app responds instantly when a request arrives. **SSH / exec access** — the ability to run commands inside a running container is essential for debugging, database migrations that need supervision, and one-off tasks. Any platform that blocks this is making operational work harder than it needs to be. **Predictable billing** — usage-based pricing is not inherently bad, but you need to be able to estimate your monthly cost before deploying. Platforms that express pricing as “per CPU-second” make this impossible without running the app first. **Co-located databases** — your database should run on the same private network as your application. Network latency between app and database is one of the most impactful performance factors, and it&#39;s one most PaaS platforms handle poorly. **Docker support** — if your app runs in Docker locally, it should run in Docker in production. Platforms that force you into language-specific buildpacks add a layer of abstraction that causes subtle production/development divergence. **Fixed monthly pricing** — the best platform for most developers is one where a $X/month plan means exactly $X, not “$X plus whatever your app consumed this month.” ## The Bottom Line Heroku leaving the free tier was disruptive, but the replacements are genuinely better for most use cases. Railway is better for simple apps with variable traffic. Fly.io is better for global distribution. <a href="https://pads.zapf.in/s/Peed1RfUlH">wordpress 99.9 uptime cheap wordpress hosting no cpanel wordpress hosting no renewal hike</a> is better for HTTP services that don&#39;t need filesystem persistence. For developers who want full Docker support, SSH access, co-located databases, and predictable fixed pricing, the answer isn&#39;t any of Heroku&#39;s direct successors — it&#39;s platforms built specifically for container-native deployment with developer experience as the primary design constraint. The era of paying Heroku prices for Heroku limitations is over. The alternatives have caught up.</p>
]]></content:encoded>
      <guid>//sharkflood8.bravejournal.net/the-best-heroku-alternatives-in-2025-for-developers-who-actually-need-control</guid>
      <pubDate>Sun, 29 Mar 2026 11:08:15 +0000</pubDate>
    </item>
    <item>
      <title>How to Deploy a Node.js App to Cloud Hosting Without Touching a Server</title>
      <link>//sharkflood8.bravejournal.net/how-to-deploy-a-node-js-app-to-cloud-hosting-without-touching-a-server</link>
      <description>&lt;![CDATA[Deploying a Node.js application used to mean SSH keys, Nginx configs, PM2 process managers, and a mental checklist that lived only in your head. That era is over. Here&#39;s how modern cloud deployment works — and why it&#39;s better for every type of Node.js project. ## What Modern Node.js Deployment Looks Like The new baseline for deploying Node.js apps is Git-driven and container-native. You connect your repository, define your build (or let the platform detect it automatically), and every push to your main branch becomes a live deployment. No server login required. Under the hood, the platform: - Detects your Node.js version from \.nvmrc\ or \package.json\ - Runs \npm install\ (or \yarn\/\pnpm\) in an isolated build environment - Executes your start command - Wraps the result in a container with resource limits - Routes traffic through a reverse proxy with automatic SSL You get all the reliability of containerized infrastructure without writing a single \Dockerfile\. ## Setting Up Your Node.js App for Cloud Deployment Before connecting your repo, make sure your project is deployment-ready: \\1. Define your start command in package.json\\ \\\json &#34;scripts&#34;: &#34;start&#34;: &#34;node server.js&#34; \\\ The platform will look for \npm start\ by default. If you&#39;re using a framework like Express, Fastify, or Koa, make sure your entry point is clearly defined. \\2. Specify your Node.js version\\ \\\ // .nvmrc 20.11.0 \\\ Pinning your Node version prevents subtle production/development environment differences that cause &#34;works on my machine&#34; bugs. \\3. Use environment variables for configuration\\ Never hardcode database URLs, API keys, or port numbers. Use \process.env.DATABASE\URL\, \process.env.PORT\, etc. Cloud platforms inject these at runtime from a secure env var store. \\4. Listen on the right port\\ \\\javascript const port = process.env.PORT || 3000; app.listen(port); \\\ Cloud platforms typically inject \PORT\ dynamically. Always read it from the environment. ## Express.js Deployment Checklist For Express apps specifically: - Set \NODE\ENV=production\ — Express disables debug output and enables response caching - Disable \x-powered-by\ header: \app.disable(&#39;x-powered-by&#39;)\ - Use a production-grade body parser with size limits - Add a health check endpoint: \app.get(&#39;/health&#39;, (req, res) =  res.json( status: &#39;ok&#39; ))\ The health check endpoint is critical — cloud platforms use it to verify your app started successfully before routing traffic to it. ## Next.js and SSR Apps Next.js apps have specific deployment requirements. For standalone output: \\\javascript // next.config.js module.exports = output: &#39;standalone&#39; \\\ This produces a minimal production build that cloud platforms can run efficiently. Start command: \node .next/standalone/server.js\. For API routes and server-side rendering, your app needs to stay warm — serverless cold starts hurt SSR performance significantly. Container-based cloud hosting keeps your Node process running persistently, eliminating this problem entirely. ## Environment Variables and Secrets Production Node.js apps have secrets: database passwords, JWT signing keys, third-party API credentials. The right way to handle these on a cloud platform: 1. Never commit them to your repository — not even in \.env\ files 2. Add them through the platform&#39;s env var management UI or CLI 3. Access them in code via \process.env\ 4. Rotate them without redeploying (just restart the container) Good cloud platforms let you manage env vars without redeploying — change a value, restart, done. No code change needed. ## Monitoring Your Node.js App in Production Once deployed, you need visibility into what&#39;s happening: \\Container logs\\ — your \console.log()\ and \console.error()\ output, streamed in real time. No need for a separate logging service for most apps. \\Resource usage\\ — CPU and memory consumption. Node.js apps with memory leaks will show a slow upward memory trend over time. Catching this early saves outages. \\Uptime monitoring\\ — your health check endpoint should be polled regularly. heroku alternative track uptime percentage and surface it in a dashboard. \\Deployment history\\ — every deploy should be recorded with its commit SHA, so you can roll back to any previous version in seconds. ## Scaling Node.js on Cloud Hosting Node.js is single-threaded but handles I/O concurrency well. For most web apps, a single container with adequate memory (512MB–1GB) handles substantial traffic. When you need more: - \\Vertical scaling\\: increase the memory/CPU allocation for your container — usually a plan upgrade - \\Autoscaling\\: some platforms monitor CPU and RAM and alert you when you&#39;re consistently hitting limits, triggering an upgrade automatically The key metric to watch isn&#39;t raw CPU percentage — it&#39;s whether your event loop is staying unblocked. High CPU on Node.js usually means synchronous computation in the request path, not just high traffic. ## The Bottom Line Deploying Node.js to cloud hosting in 2025 should take under 10 minutes for a new project. If it&#39;s taking longer, the platform is getting in your way. Git push, environment variables, health checks, logs — that&#39;s the entire operational surface you should need to touch. Everything else should be invisible.]]&gt;</description>
      <content:encoded><![CDATA[<p>Deploying a Node.js application used to mean SSH keys, Nginx configs, PM2 process managers, and a mental checklist that lived only in your head. That era is over. Here&#39;s how modern cloud deployment works — and why it&#39;s better for every type of Node.js project. ## What Modern Node.js Deployment Looks Like The new baseline for deploying Node.js apps is Git-driven and container-native. You connect your repository, define your build (or let the platform detect it automatically), and every push to your main branch becomes a live deployment. No server login required. Under the hood, the platform: – Detects your Node.js version from `.nvmrc` or `package.json` – Runs `npm install` (or `yarn`/`pnpm`) in an isolated build environment – Executes your start command – Wraps the result in a container with resource limits – Routes traffic through a reverse proxy with automatic SSL You get all the reliability of containerized infrastructure without writing a single `Dockerfile`. ## Setting Up Your Node.js App for Cloud Deployment Before connecting your repo, make sure your project is deployment-ready: **1. Define your start command in package.json** ```json “scripts”: “start”: “node server.js” ``` The platform will look for `npm start` by default. If you&#39;re using a framework like Express, Fastify, or Koa, make sure your entry point is clearly defined. **2. Specify your Node.js version** ``` // .nvmrc 20.11.0 ``` Pinning your Node version prevents subtle production/development environment differences that cause “works on my machine” bugs. **3. Use environment variables for configuration** Never hardcode database URLs, API keys, or port numbers. Use `process.env.DATABASE_URL`, `process.env.PORT`, etc. Cloud platforms inject these at runtime from a secure env var store. **4. Listen on the right port** ```javascript const port = process.env.PORT || 3000; app.listen(port); ``` Cloud platforms typically inject `PORT` dynamically. Always read it from the environment. ## Express.js Deployment Checklist For Express apps specifically: – Set `NODE_ENV=production` — Express disables debug output and enables response caching – Disable `x-powered-by` header: `app.disable(&#39;x-powered-by&#39;)` – Use a production-grade body parser with size limits – Add a health check endpoint: `app.get(&#39;/health&#39;, (req, res) =&gt; res.json( status: &#39;ok&#39; ))` The health check endpoint is critical — cloud platforms use it to verify your app started successfully before routing traffic to it. ## Next.js and SSR Apps Next.js apps have specific deployment requirements. For standalone output: ```javascript // next.config.js module.exports = output: &#39;standalone&#39; ``` This produces a minimal production build that cloud platforms can run efficiently. Start command: `node .next/standalone/server.js`. For API routes and server-side rendering, your app needs to stay warm — serverless cold starts hurt SSR performance significantly. Container-based cloud hosting keeps your Node process running persistently, eliminating this problem entirely. ## Environment Variables and Secrets Production Node.js apps have secrets: database passwords, JWT signing keys, third-party API credentials. The right way to handle these on a cloud platform: 1. Never commit them to your repository — not even in `.env` files 2. Add them through the platform&#39;s env var management UI or CLI 3. Access them in code via `process.env` 4. Rotate them without redeploying (just restart the container) Good cloud platforms let you manage env vars without redeploying — change a value, restart, done. No code change needed. ## Monitoring Your Node.js App in Production Once deployed, you need visibility into what&#39;s happening: **Container logs** — your `console.log()` and `console.error()` output, streamed in real time. No need for a separate logging service for most apps. **Resource usage** — CPU and memory consumption. Node.js apps with memory leaks will show a slow upward memory trend over time. Catching this early saves outages. **Uptime monitoring** — your health check endpoint should be polled regularly. <a href="https://white-shea-2.technetbloggers.de/wordpress-security-what-your-hosting-choice-actually-controls-1774779283">heroku alternative</a> track uptime percentage and surface it in a dashboard. **Deployment history** — every deploy should be recorded with its commit SHA, so you can roll back to any previous version in seconds. ## Scaling Node.js on Cloud Hosting Node.js is single-threaded but handles I/O concurrency well. For most web apps, a single container with adequate memory (512MB–1GB) handles substantial traffic. When you need more: – **Vertical scaling**: increase the memory/CPU allocation for your container — usually a plan upgrade – **Autoscaling**: some platforms monitor CPU and RAM and alert you when you&#39;re consistently hitting limits, triggering an upgrade automatically The key metric to watch isn&#39;t raw CPU percentage — it&#39;s whether your event loop is staying unblocked. High CPU on Node.js usually means synchronous computation in the request path, not just high traffic. ## The Bottom Line Deploying Node.js to cloud hosting in 2025 should take under 10 minutes for a new project. If it&#39;s taking longer, the platform is getting in your way. Git push, environment variables, health checks, logs — that&#39;s the entire operational surface you should need to touch. Everything else should be invisible.</p>
]]></content:encoded>
      <guid>//sharkflood8.bravejournal.net/how-to-deploy-a-node-js-app-to-cloud-hosting-without-touching-a-server</guid>
      <pubDate>Sun, 29 Mar 2026 10:52:47 +0000</pubDate>
    </item>
    <item>
      <title>WordPress Email Deliverability: Why Your Emails Go to Spam and How to Fix It</title>
      <link>//sharkflood8.bravejournal.net/wordpress-email-deliverability-why-your-emails-go-to-spam-and-how-to-fix-it</link>
      <description>&lt;![CDATA[WordPress sends emails constantly: contact form submissions, WooCommerce order confirmations, password resets, new user notifications, admin alerts. If these emails are going to spam — or not arriving at all — you have an email deliverability problem. Here&#39;s why it happens and how to fix it permanently. ## Why WordPress Emails Fail to Deliver By default, WordPress sends email using PHP&#39;s \mail()\ function. This calls the local mail server (Sendmail or Postfix) on your hosting server, which then attempts to deliver the email directly to the recipient&#39;s mail server. The problem: this mechanism has no authentication. The email arrives at Gmail or Outlook claiming to be from \info@yoursite.com\, but it comes from an IP address that has no cryptographic proof that it&#39;s authorized to send email for \yoursite.com\. Modern spam filters treat this as suspicious. Specific failure reasons: \\No SPF record\\: SPF (Sender Policy Framework) lists which IP addresses are authorized to send email for your domain. If your hosting server&#39;s IP isn&#39;t in your SPF record — and it usually isn&#39;t, because you didn&#39;t add it — receiving mail servers see the email as potentially spoofed. \\No DKIM signature\\: DKIM (DomainKeys Identified Mail) adds a cryptographic signature to each email that proves it was sent by an authorized server. PHP&#39;s \mail()\ doesn&#39;t add DKIM signatures by default. Without DKIM, your email is unverified. \\No DMARC policy\\: DMARC ties SPF and DKIM together with a policy telling receiving servers what to do with emails that fail authentication. Without DMARC, there&#39;s no policy — emails that fail SPF/DKIM may or may not be delivered, depending on the receiving server&#39;s judgment. \\Shared IP reputation\\: On shared hosting, many sites share the same outbound IP address. If any of those sites sends spam, the shared IP gets a poor reputation. Your legitimate transactional emails inherit that bad reputation and go to spam. \\Reverse DNS mismatch\\: The IP address your server sends from should have a reverse DNS record that matches your domain. Shared hosting often fails this check. ## The Solution: Authenticated SMTP Stop using PHP&#39;s \mail()\ function. Route all WordPress email through an authenticated SMTP service that handles SPF, DKIM, and DMARC correctly. Your options: ### Mailgun (Recommended for High Volume) Mailgun is built for transactional email — order confirmations, password resets, notifications. The free tier handles 1,000 emails/month. Paid plans start at $35/month for 50,000 emails. Setup: 1. Create Mailgun account 2. Add and verify your domain 3. Mailgun generates DKIM keys and gives you DNS records to add 4. Add the DNS records at your domain registrar (takes up to 48 hours to propagate) 5. Configure WP Mail SMTP with Mailgun API credentials ### SendGrid (Good for High Volume) SendGrid is similar to Mailgun. Free tier: 100 emails/day. Paid from $20/month. The SendGrid WordPress plugin integrates directly without needing WP Mail SMTP. ### Amazon SES (Cheapest at Scale) Amazon SES costs $0.10 per 1,000 emails — the cheapest option at volume. Requires more setup and starts in &#34;sandbox mode&#34; that restricts who you can email until you request production access. ### Postmark (Best Deliverability for Transactional Email) Postmark specializes in transactional email with a focus on deliverability. More expensive ($15/month for 10,000 emails) but consistently excellent inbox placement rates. ### Google Workspace SMTP (Simple but Limited) If you use Google Workspace for business email, you can send WordPress emails through Gmail&#39;s SMTP servers. Free with your Google Workspace subscription. Limits: 2,000 emails/day, no API — uses SMTP auth. Not recommended for WooCommerce stores with high order volume. Fine for small sites with mostly contact form email. ## Installing and Configuring WP Mail SMTP WP Mail SMTP is the standard WordPress plugin for routing email through external providers. Install it from the WordPress plugin directory. ### Configuration for Mailgun \\\ Mailer: Mailgun Domain: yoursite.com Private API Key: (from Mailgun dashboard) Send From Email: noreply@yoursite.com Send From Name: Your Site Name \\\ ### Configuration for SendGrid \\\ Mailer: SendGrid API Key: (from SendGrid dashboard, needs Mail Send permission) Send From Email: noreply@yoursite.com Send From Name: Your Site Name \\\ ### Configuration for Generic SMTP If your provider isn&#39;t in WP Mail SMTP&#39;s supported list: \\\ Mailer: Other SMTP SMTP Host: smtp.yourprovider.com Encryption: TLS SMTP Port: 587 Authentication: On SMTP Username: your-smtp-username SMTP Password: your-smtp-password Send From Email: noreply@yoursite.com \\\ After configuring, use WP Mail SMTP&#39;s built-in Email Test to send a test message and verify delivery. ## DNS Configuration: SPF, DKIM, DMARC These three DNS records are the foundation of email authentication. You configure them at your domain registrar&#39;s DNS settings. ### SPF Record SPF specifies which servers are allowed to send email for your domain. If you&#39;re sending only through Mailgun: \\\ TXT record: v=spf1 include:mailgun.org ~all \\\ If you&#39;re also sending from Google Workspace: \\\ TXT record: v=spf1 include:mailgun.org include:\spf.google.com ~all \\\ If you&#39;re sending from multiple services: \\\ TXT record: v=spf1 include:mailgun.org include:\spf.google.com include:sendgrid.net ~all \\\ Rules: - Only one SPF record per domain (multiple SPF records cause failures) - \-all\ (hard fail) is stricter than \~all\ (soft fail) — use \~all\ until you&#39;re confident all legitimate sending sources are listed - SPF has a 10-lookup limit — using many \include:\ statements can exceed this ### DKIM Record DKIM adds a cryptographic signature to outgoing emails. Each email service generates a DKIM key pair and gives you the public key to add as a DNS record. Mailgun provides a DKIM record that looks like: \\\ Name: mailo.\domainkey.yoursite.com Type: TXT Value: k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GN... \\\ Add exactly what your email service provides. The \\domainkey\ subdomain is standard; the prefix (e.g., \mailo\) is specific to the service. Verify DKIM is working with a tool like mail-tester.com or MXToolbox&#39;s DKIM checker. ### DMARC Record DMARC tells receiving servers what to do when emails fail SPF/DKIM checks. Start with a monitoring-only policy, then tighten it once you&#39;ve verified all legitimate sending is authenticated. Start here (monitoring only, no email blocked): \\\ Name: \dmarc.yoursite.com Type: TXT Value: v=DMARC1; p=none; rua=mailto:dmarc@yoursite.com \\\ \rua=mailto:dmarc@yoursite.com\ sends aggregate reports to that address. These reports show who is sending email claiming to be from your domain — useful for finding unauthenticated senders. After reviewing reports and confirming all legitimate email is authenticated, move to quarantine: \\\ v=DMARC1; p=quarantine; pct=25; rua=mailto:dmarc@yoursite.com \\\ \p=quarantine\ sends failing emails to spam instead of blocking. \pct=25\ applies the policy to 25% of failing emails — a gradual rollout. Once confident, move to reject: \\\ v=DMARC1; p=reject; rua=mailto:dmarc@yoursite.com \\\ \p=reject\ tells receiving servers to discard emails that fail DMARC authentication. This is the final goal — it completely blocks email spoofing of your domain. ## WooCommerce Email Configuration WooCommerce sends several email types that need to work reliably: - New order (to store owner) - Processing order (to customer) - Completed order (to customer) - Refund (to customer) - Password reset (to customer) - New customer registration Each email type is configurable under WooCommerce → Settings → Emails. Important settings: \\&#34;From&#34; email address\\: Should match an address on your authenticated domain. Using a Gmail address as the &#34;From&#34; while sending through a different SMTP server causes DMARC failures. \\\ From: orders@yoursite.com # Correct — matches your domain From: yourname@gmail.com # Wrong — causes DMARC issues if sending via Mailgun \\\ \\Reply-To\\: Can be a different address. If you want replies to go to a Gmail inbox, set Reply-To to your Gmail without using it as the From address. ### Testing WooCommerce Emails Install the WooCommerce Email Test plugin or use WP Mail SMTP&#39;s email log to verify: 1. Place a test order (use WooCommerce&#39;s &#34;order by cheque&#34; to avoid payment) 2. Check that the customer order confirmation arrived in inbox (not spam) 3. Check that the admin new order notification arrived 4. Use mail-tester.com to check your spam score before sending real orders ## Diagnosing Email Delivery Problems ### Email not sending at all Check WP Mail SMTP&#39;s email log (requires Pro, or use the free Email Log plugin). If there&#39;s fast wordpress hosting, of the email being sent, the problem is in WordPress — a plugin not calling \wp\mail()\, a fatal PHP error during sending, or WP Mail SMTP misconfiguration. Check PHP error log for SMTP connection errors: \\\bash # Via SSH tail -f /var/log/php-fpm/error.log | grep mail \\\ ### Email sending but going to spam Run your email through mail-tester.com: send an email to the address they provide, then check your score. The report shows exactly which checks failed. Common causes: - SPF record missing or incorrect - DKIM not configured - Sending from an IP with poor reputation (switch to API-based sending instead of SMTP) - Email content triggering spam filters (check for spammy phrases) ### Emails arriving but images broken WordPress email images reference your domain. If Cloudflare or a CDN is doing image optimization, images in emails may not load correctly. Use isolated wordpress hosting, cloudflare wordpress hosting for images in email templates and ensure they&#39;re accessible without authentication. ### WooCommerce order emails not sending Most commonly caused by: 1. WordPress&#39;s default \mail()\ failing silently — install WP Mail SMTP and configure a real SMTP provider 2. The &#34;New order&#34; email is disabled in WooCommerce → Settings → Emails 3. A plugin conflict intercepting \wp\_mail()\ — deactivate plugins one by one to identify ## Transactional vs Marketing Email Keep transactional email (order confirmations, password resets, account notifications) separate from marketing email (newsletters, promotional campaigns). Mixing them on the same IP/domain means that if your newsletter gets flagged as spam, your order confirmation emails suffer. Most SMTP providers support this separation: - Mailgun: separate domain streams for transactional vs marketing - SendGrid: separate IP addresses and subdomains - Postmark: separate message streams For newsletters and marketing, use a dedicated platform (Mailchimp, Klaviyo, ActiveCampaign) rather than sending through the same SMTP service as your transactional email. They manage list hygiene, unsubscribes, and deliverability at scale. ## The Complete Email Checklist - \[ \] WP Mail SMTP installed and configured with an authenticated SMTP provider - \[ \] SPF record added to DNS for your domain - \[ \] DKIM keys generated by your SMTP provider, DNS records added - \[ \] DMARC record added (start with \p=none\, move to \p=reject\ after verification) - \[ \] WooCommerce &#34;From&#34; address uses your domain, not Gmail - \[ \] Email test sent and received in inbox (not spam) - \[ \] mail-tester.com score above 9/10 - \[ \] WooCommerce order confirmation email tested end-to-end - \[ \] Contact form email tested - \[ \] Password reset email tested Getting email deliverability right is a one-time setup that prevents an ongoing problem. Customers who don&#39;t receive their order confirmation email contact support. Customers who don&#39;t receive password reset emails can&#39;t log back in. Fixing this takes an hour and eliminates an entire category of customer service friction.]]&gt;</description>
      <content:encoded><![CDATA[<p>WordPress sends emails constantly: contact form submissions, WooCommerce order confirmations, password resets, new user notifications, admin alerts. If these emails are going to spam — or not arriving at all — you have an email deliverability problem. Here&#39;s why it happens and how to fix it permanently. ## Why WordPress Emails Fail to Deliver By default, WordPress sends email using PHP&#39;s `mail()` function. This calls the local mail server (Sendmail or Postfix) on your hosting server, which then attempts to deliver the email directly to the recipient&#39;s mail server. The problem: this mechanism has no authentication. The email arrives at Gmail or Outlook claiming to be from `info@yoursite.com`, but it comes from an IP address that has no cryptographic proof that it&#39;s authorized to send email for `yoursite.com`. Modern spam filters treat this as suspicious. Specific failure reasons: **No SPF record**: SPF (Sender Policy Framework) lists which IP addresses are authorized to send email for your domain. If your hosting server&#39;s IP isn&#39;t in your SPF record — and it usually isn&#39;t, because you didn&#39;t add it — receiving mail servers see the email as potentially spoofed. **No DKIM signature**: DKIM (DomainKeys Identified Mail) adds a cryptographic signature to each email that proves it was sent by an authorized server. PHP&#39;s `mail()` doesn&#39;t add DKIM signatures by default. Without DKIM, your email is unverified. **No DMARC policy**: DMARC ties SPF and DKIM together with a policy telling receiving servers what to do with emails that fail authentication. Without DMARC, there&#39;s no policy — emails that fail SPF/DKIM may or may not be delivered, depending on the receiving server&#39;s judgment. **Shared IP reputation**: On shared hosting, many sites share the same outbound IP address. If any of those sites sends spam, the shared IP gets a poor reputation. Your legitimate transactional emails inherit that bad reputation and go to spam. **Reverse DNS mismatch**: The IP address your server sends from should have a reverse DNS record that matches your domain. Shared hosting often fails this check. ## The Solution: Authenticated SMTP Stop using PHP&#39;s `mail()` function. Route all WordPress email through an authenticated SMTP service that handles SPF, DKIM, and DMARC correctly. Your options: ### Mailgun (Recommended for High Volume) Mailgun is built for transactional email — order confirmations, password resets, notifications. The free tier handles 1,000 emails/month. Paid plans start at $35/month for 50,000 emails. Setup: 1. Create Mailgun account 2. Add and verify your domain 3. Mailgun generates DKIM keys and gives you DNS records to add 4. Add the DNS records at your domain registrar (takes up to 48 hours to propagate) 5. Configure WP Mail SMTP with Mailgun API credentials ### SendGrid (Good for High Volume) SendGrid is similar to Mailgun. Free tier: 100 emails/day. Paid from $20/month. The SendGrid WordPress plugin integrates directly without needing WP Mail SMTP. ### Amazon SES (Cheapest at Scale) Amazon SES costs $0.10 per 1,000 emails — the cheapest option at volume. Requires more setup and starts in “sandbox mode” that restricts who you can email until you request production access. ### Postmark (Best Deliverability for Transactional Email) Postmark specializes in transactional email with a focus on deliverability. More expensive ($15/month for 10,000 emails) but consistently excellent inbox placement rates. ### Google Workspace SMTP (Simple but Limited) If you use Google Workspace for business email, you can send WordPress emails through Gmail&#39;s SMTP servers. Free with your Google Workspace subscription. Limits: 2,000 emails/day, no API — uses SMTP auth. Not recommended for WooCommerce stores with high order volume. Fine for small sites with mostly contact form email. ## Installing and Configuring WP Mail SMTP WP Mail SMTP is the standard WordPress plugin for routing email through external providers. Install it from the WordPress plugin directory. ### Configuration for Mailgun ``` Mailer: Mailgun Domain: yoursite.com Private API Key: (from Mailgun dashboard) Send From Email: noreply@yoursite.com Send From Name: Your Site Name ``` ### Configuration for SendGrid ``` Mailer: SendGrid API Key: (from SendGrid dashboard, needs Mail Send permission) Send From Email: noreply@yoursite.com Send From Name: Your Site Name ``` ### Configuration for Generic SMTP If your provider isn&#39;t in WP Mail SMTP&#39;s supported list: ``` Mailer: Other SMTP SMTP Host: smtp.yourprovider.com Encryption: TLS SMTP Port: 587 Authentication: On SMTP Username: your-smtp-username SMTP Password: your-smtp-password Send From Email: noreply@yoursite.com ``` After configuring, use WP Mail SMTP&#39;s built-in Email Test to send a test message and verify delivery. ## DNS Configuration: SPF, DKIM, DMARC These three DNS records are the foundation of email authentication. You configure them at your domain registrar&#39;s DNS settings. ### SPF Record SPF specifies which servers are allowed to send email for your domain. If you&#39;re sending only through Mailgun: ``` TXT record: v=spf1 include:mailgun.org ~all ``` If you&#39;re also sending from Google Workspace: ``` TXT record: v=spf1 include:mailgun.org include:_spf.google.com ~all ``` If you&#39;re sending from multiple services: ``` TXT record: v=spf1 include:mailgun.org include:_spf.google.com include:sendgrid.net ~all ``` Rules: – Only one SPF record per domain (multiple SPF records cause failures) – `-all` (hard fail) is stricter than `~all` (soft fail) — use `~all` until you&#39;re confident all legitimate sending sources are listed – SPF has a 10-lookup limit — using many `include:` statements can exceed this ### DKIM Record DKIM adds a cryptographic signature to outgoing emails. Each email service generates a DKIM key pair and gives you the public key to add as a DNS record. Mailgun provides a DKIM record that looks like: ``` Name: mailo._domainkey.yoursite.com Type: TXT Value: k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GN... ``` Add exactly what your email service provides. The `_domainkey` subdomain is standard; the prefix (e.g., `mailo`) is specific to the service. Verify DKIM is working with a tool like mail-tester.com or MXToolbox&#39;s DKIM checker. ### DMARC Record DMARC tells receiving servers what to do when emails fail SPF/DKIM checks. Start with a monitoring-only policy, then tighten it once you&#39;ve verified all legitimate sending is authenticated. Start here (monitoring only, no email blocked): ``` Name: _dmarc.yoursite.com Type: TXT Value: v=DMARC1; p=none; rua=mailto:dmarc@yoursite.com ``` `rua=mailto:dmarc@yoursite.com` sends aggregate reports to that address. These reports show who is sending email claiming to be from your domain — useful for finding unauthenticated senders. After reviewing reports and confirming all legitimate email is authenticated, move to quarantine: ``` v=DMARC1; p=quarantine; pct=25; rua=mailto:dmarc@yoursite.com ``` `p=quarantine` sends failing emails to spam instead of blocking. `pct=25` applies the policy to 25% of failing emails — a gradual rollout. Once confident, move to reject: ``` v=DMARC1; p=reject; rua=mailto:dmarc@yoursite.com ``` `p=reject` tells receiving servers to discard emails that fail DMARC authentication. This is the final goal — it completely blocks email spoofing of your domain. ## WooCommerce Email Configuration WooCommerce sends several email types that need to work reliably: – New order (to store owner) – Processing order (to customer) – Completed order (to customer) – Refund (to customer) – Password reset (to customer) – New customer registration Each email type is configurable under WooCommerce → Settings → Emails. Important settings: **“From” email address**: Should match an address on your authenticated domain. Using a Gmail address as the “From” while sending through a different SMTP server causes DMARC failures. ``` From: orders@yoursite.com # Correct — matches your domain From: yourname@gmail.com # Wrong — causes DMARC issues if sending via Mailgun ``` **Reply-To**: Can be a different address. If you want replies to go to a Gmail inbox, set Reply-To to your Gmail without using it as the From address. ### Testing WooCommerce Emails Install the WooCommerce Email Test plugin or use WP Mail SMTP&#39;s email log to verify: 1. Place a test order (use WooCommerce&#39;s “order by cheque” to avoid payment) 2. Check that the customer order confirmation arrived in inbox (not spam) 3. Check that the admin new order notification arrived 4. Use mail-tester.com to check your spam score before sending real orders ## Diagnosing Email Delivery Problems ### Email not sending at all Check WP Mail SMTP&#39;s email log (requires Pro, or use the free Email Log plugin). If there&#39;s <a href="https://apexweave.com">fast wordpress hosting,</a> of the email being sent, the problem is in WordPress — a plugin not calling `wp_mail()`, a fatal PHP error during sending, or WP Mail SMTP misconfiguration. Check PHP error log for SMTP connection errors: ```bash # Via SSH tail -f /var/log/php-fpm/error.log | grep mail ``` ### Email sending but going to spam Run your email through mail-tester.com: send an email to the address they provide, then check your score. The report shows exactly which checks failed. Common causes: – SPF record missing or incorrect – DKIM not configured – Sending from an IP with poor reputation (switch to API-based sending instead of SMTP) – Email content triggering spam filters (check for spammy phrases) ### Emails arriving but images broken WordPress email images reference your domain. If Cloudflare or a CDN is doing image optimization, images in emails may not load correctly. Use <a href="https://apexweave.com/free-tier.php">isolated wordpress hosting, cloudflare wordpress hosting</a> for images in email templates and ensure they&#39;re accessible without authentication. ### WooCommerce order emails not sending Most commonly caused by: 1. WordPress&#39;s default `mail()` failing silently — install WP Mail SMTP and configure a real SMTP provider 2. The “New order” email is disabled in WooCommerce → Settings → Emails 3. A plugin conflict intercepting `wp_mail()` — deactivate plugins one by one to identify ## Transactional vs Marketing Email Keep transactional email (order confirmations, password resets, account notifications) separate from marketing email (newsletters, promotional campaigns). Mixing them on the same IP/domain means that if your newsletter gets flagged as spam, your order confirmation emails suffer. Most SMTP providers support this separation: – Mailgun: separate domain streams for transactional vs marketing – SendGrid: separate IP addresses and subdomains – Postmark: separate message streams For newsletters and marketing, use a dedicated platform (Mailchimp, Klaviyo, ActiveCampaign) rather than sending through the same SMTP service as your transactional email. They manage list hygiene, unsubscribes, and deliverability at scale. ## The Complete Email Checklist – [ ] WP Mail SMTP installed and configured with an authenticated SMTP provider – [ ] SPF record added to DNS for your domain – [ ] DKIM keys generated by your SMTP provider, DNS records added – [ ] DMARC record added (start with `p=none`, move to `p=reject` after verification) – [ ] WooCommerce “From” address uses your domain, not Gmail – [ ] Email test sent and received in inbox (not spam) – [ ] mail-tester.com score above 9/10 – [ ] WooCommerce order confirmation email tested end-to-end – [ ] Contact form email tested – [ ] Password reset email tested Getting email deliverability right is a one-time setup that prevents an ongoing problem. Customers who don&#39;t receive their order confirmation email contact support. Customers who don&#39;t receive password reset emails can&#39;t log back in. Fixing this takes an hour and eliminates an entire category of customer service friction.</p>
]]></content:encoded>
      <guid>//sharkflood8.bravejournal.net/wordpress-email-deliverability-why-your-emails-go-to-spam-and-how-to-fix-it</guid>
      <pubDate>Sun, 29 Mar 2026 09:56:46 +0000</pubDate>
    </item>
  </channel>
</rss>