Guides Guide

PrestaShop Email Deliverability - SMTP, SPF, DKIM Setup Guide

Fix PrestaShop emails landing in spam: configure SMTP, set up SPF/DKIM/DMARC, use transactional email services, and PS 8/9 email settings guide.

Order confirmations going to spam — the #1 email complaint we hear

A customer pays. PrestaShop's mail log says "sent." The confirmation email never arrives, or it lands in the Promotions tab, or it sits in spam for six hours. The customer panics, opens a chargeback, leaves a one-star review, and emails support asking "did you take my money?" We've watched this happen on more shops than we can count, and in 2026 it is still the single most common email problem in PrestaShop.

The fix is rarely something inside PrestaShop. Deliverability is decided by the receiving mail server (Gmail, Outlook, Yahoo) and what they decide depends on how you authenticate, what reputation your sending IP has, and whether your DNS tells the truth about who is allowed to send as your domain. PrestaShop's job is just to hand the message off cleanly.

PHP mail() is theatre

A fresh PrestaShop install sends through PHP's mail() function. This is the default, and it is the worst option we can think of for a production shop:

  • No authentication. The message arrives with no proof that you authorised it. Gmail and Outlook treat unauthenticated mail as guilty until proven innocent.
  • Shared IP, shared reputation. On shared hosting your mail leaves from the same IP as 200 other sites. One of them spams, you all suffer.
  • No DKIM signature. mail() doesn't sign anything cryptographically. There is nothing for the recipient to verify.
  • Bare-minimum headers. Spam filters score that as suspicious before they even look at the body.
If your shop is still using mail(), switching to real SMTP is the single change that will fix more deliverability problems than every other step on this page combined. Do it first.

What actually gets a message marked as spam

  • From-address mismatch. Sending from noreply@yourstore.com while your DNS has no SPF record allowing your server's IP to do so.
  • Image-heavy templates. Default PrestaShop templates are picture-rich. A bad image-to-text ratio is a spam signal on its own.
  • Missing plain-text part. PrestaShop sends multipart by default, but custom templates and translation modules can quietly break the plain-text alternative.
  • Broken links. Spam filters resolve URLs in your message. If your storefront is in maintenance mode, has a bad SSL chain, or 500s, your email gets flagged.
  • Encoding garbage. Shops with Polish, Czech, German, French diacritics produce mojibake the moment one piece of the chain isn't UTF-8.

PrestaShop email configuration by version

Email configuration in PrestaShop 8 Back Office.

The choice between sendmail and SMTP, email format, log toggle, and DKIM signing. If your order confirmations are going to spam, this is where to start.

PrestaShop 8 Back Office Email settings page showing sendmail vs SMTP choice, DKIM configuration, and email logging

The settings page has stayed in roughly the same place. The library underneath changed completely in PS 9.

PrestaShop 1.6 and 1.7

Advanced Parameters → E-mail. Pick "Set my own SMTP parameters" and enter server, port, encryption, username, password. PS 1.6 uses PHP's own SMTP handling; PS 1.7 brought in Swift Mailer. Encryption choices:

  • TLS (port 587): The modern default. STARTTLS, the right answer almost everywhere.
  • SSL (port 465): Older implicit TLS. Some legacy hosts still require it.
  • None (port 25): Unencrypted. Don't.

PrestaShop 8.x

Same screen, same interface. PS 8 ships the final Swift Mailer release with better error reporting — when SMTP fails you actually get a useful line in var/logs/ instead of a silent drop.

PrestaShop 9 — Symfony Mailer

PS 9 retires Swift Mailer (it's been EOL upstream for years) and replaces it with Symfony Mailer. The admin UI looks identical, but everything underneath has changed:

  • DSN-based config. Internally the transport is a URI: smtp://user:password@server:port.
  • TLS auto-detect. Port 587 will auto-negotiate STARTTLS. The "encryption" dropdown sometimes behaves differently after an 8 → 9 upgrade — re-test.
  • Stricter validation. Symfony Mailer cares about envelope sender matching the From header, and it validates TLS certificates properly.
  • Module breakage. Any module that imports Swift_Message or Swift_SmtpTransport stops working on PS 9 until it is updated.
# PS 9 internal DSN examples (configured via admin UI)
smtp://user:password@mail.example.com:587      # STARTTLS
smtps://user:password@mail.example.com:465     # Implicit TLS
smtp://your%40gmail.com:app-pass@smtp.gmail.com:587  # Gmail
native://default                                # PHP mail() (not recommended)
Always re-test email after any 8 → 9 upgrade. We've seen self-signed certificates, non-standard ports, and loosely-implemented SMTP servers all stop working the moment Symfony Mailer takes over.

The "send test email" button

Every version has it. It is useful, but it confirms one thing only: that your shop can open an SMTP connection. It does not confirm the message reached an inbox. Send real test orders to a Gmail address, an Outlook address, and an address on your own domain — those three cover roughly 90% of what your customers use.

Domain authentication — SPF, DKIM, DMARC

SPF, DKIM, and DMARC are three DNS records that together prove your mail is legitimate. Gmail and Yahoo made SPF and DKIM mandatory for bulk senders in February 2024. We treat them as mandatory for every sender, full stop.

SPF (Sender Policy Framework)

One TXT record on your domain that names the IPs and services allowed to send as you.

# Basic — allows hosting + Google
v=spf1 include:_spf.google.com include:your-hosting-provider.com ~all

# OVH
v=spf1 include:mx.ovh.com ~all

# Hostinger
v=spf1 include:_spf.hostinger.com ~all

# With Mailgun
v=spf1 include:mailgun.org include:_spf.google.com ~all

Where this goes wrong:

  • Two SPF records. Only one TXT record per domain is valid SPF. Two records cancel each other out. Combine services into a single record with multiple include: directives.
  • Too many lookups. SPF allows 10 DNS lookups total. Every include: counts, and nested includes count too. Run yours through a validator before publishing.
  • +all instead of ~all. +all tells the world anyone can send as you — which is exactly the opposite of the point. Start with ~all (softfail), tighten to -all once you're confident.
  • Subdomains aren't inherited. SPF for shop.example.com needs its own record. The parent domain does not cover it.

DKIM

DKIM cryptographically signs every outgoing message. PrestaShop does not sign DKIM — your SMTP relay, hosting provider, or transactional service does. You publish their public key in DNS and they sign with the matching private key.

  • Shared hosting (cPanel/Plesk): Usually one click in cPanel → Email Deliverability.
  • Gmail / Google Workspace: Admin console → Gmail → Authenticate email. Google hands you a TXT record.
  • Transactional services: Their domain verification wizard tells you exactly what to publish.
# DKIM TXT record example
# Name: default._domainkey.yourstore.com (selector varies by provider)
v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...

DMARC

DMARC ties SPF and DKIM together and tells the receiving server what to do when authentication fails.

# Stage 1: Monitor only
v=DMARC1; p=none; rua=mailto:dmarc-reports@yourstore.com;

# Stage 2: Quarantine failures
v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@yourstore.com;

# Stage 3: Reject failures (maximum protection)
v=DMARC1; p=reject; rua=mailto:dmarc-reports@yourstore.com;

The rua address receives aggregate XML reports — a daily list of who has tried to send mail as your domain. We pipe ours through Postmark's free DMARC monitoring because reading raw XML is not how anyone should spend Monday morning.

Roll DMARC out in stages. Two to four weeks at p=none while you read the reports and identify legitimate senders that fail. Tighten to p=quarantine for another two to four weeks. Only then move to p=reject. Going straight to reject on day one blocks mail you didn't know existed — usually a CRM or accountant sending invoices on your behalf.

SMTP on shared hosting

Most PrestaShop shops live on shared hosting. Create a dedicated mailbox (e.g. orders@yourstore.com) and use those credentials in PrestaShop — never your personal inbox.

Provider settings

# Generic cPanel
Server: mail.yourstore.com | Port: 587 | Encryption: TLS

# OVH
Server: ssl0.ovh.net | Port: 587 | Encryption: TLS

# Hostinger
Server: smtp.hostinger.com | Port: 587 | Encryption: TLS

# SiteGround
Server: yourstore.com | Port: 465 | Encryption: SSL

# Bluehost
Server: mail.yourstore.com | Port: 465 | Encryption: SSL

Gmail SMTP

SMTP configuration fields in PrestaShop 8.

When "Set my own SMTP parameters" is selected, these fields appear: server, port, username, password, encryption. This is where you point PrestaShop at Gmail, SendGrid, Mailgun, or your own mail server.

PrestaShop 8 SMTP configuration showing server, port, username, password, and encryption fields

This is what we use ourselves for mypresta.rocks — Gmail SMTP with an App Password (Google Account → Security → 2-Step Verification → App passwords). Cheap, reliable, sane for a low-volume shop.

Server: smtp.gmail.com | Port: 587 | Encryption: TLS
Username: your@gmail.com | Password: (16-char App Password)

Limits: free Gmail 500/day, Google Workspace 2,000/day. Burst too fast and Google will temporarily throttle you.

Gmail SMTP works fine for shops under roughly 30 orders a day. Above that you start hitting the cap, and customers wait up to 24 hours for their confirmation. That's the moment to move to a real transactional service.

Microsoft 365 SMTP

Server: smtp.office365.com | Port: 587 | Encryption: TLS
Username: your@yourstore.com | Password: account or App Password

Limit: 10,000 recipients/day, 30 messages/minute. Microsoft is increasingly insisting on OAuth instead of basic SMTP auth — check your tenant policy before going live.

Transactional email services

When you outgrow hosting SMTP, transactional services give you dedicated high-reputation infrastructure, DKIM signing handled for you, bounce processing, and a dashboard that tells you what actually happened to each message.

When to make the move

  • You're hitting your host's sending limits.
  • Email lands in spam even with SPF, DKIM and DMARC all green.
  • You need delivery tracking and bounce handling.
  • Your shared IP's reputation is dragging you down and you can't do anything about it.

Who's worth using

Mailgun — from $15/mo for 10K emails. Strong API, useful analytics. SMTP at smtp.mailgun.org:587.

Postmark — from $15/mo for 10K emails. Best inbox rate we've measured. Hard separation between transactional and marketing streams, which is exactly the right architecture. SMTP at smtp.postmarkapp.com:587, Server API Token in both username and password.

Amazon SES — $0.10 per 1,000 emails. The cheapest at scale by an order of magnitude. Generate SMTP credentials inside the SES console (not your AWS IAM keys). New accounts start in sandbox until you request production access. Region-specific endpoint, e.g. email-smtp.eu-west-1.amazonaws.com:587.

SendGrid — free tier 100/day, paid from $19.95/mo. Username is literally the string apikey, password is your API key. SMTP at smtp.sendgrid.net:587. The free tier shares IPs with everyone else on the free tier, so deliverability there is poor — budget for paid.

Brevo — free tier 300/day, paid from $9/mo. Built-in newsletter and CRM, EU-based (handy for GDPR). SMTP at smtp-relay.brevo.com:587. Has its own PrestaShop plugin if you want one.

Our defaults: Brevo if you want newsletters in the same place. Postmark if transactional inbox rate is what you care about. Amazon SES at high volume on a budget. Mailgun as the safe all-rounder.

How you connect

All of them speak plain SMTP, no module required. Verify the domain, publish their SPF and DKIM records, generate SMTP credentials, paste into PrestaShop, test.

Self-hosted mail

You can run your own mail server. We do — we run Mailcow for some of our infrastructure. It gives you total control, no per-email fees, no third-party reading your customer data. The cost is real ongoing sysadmin work, and getting reputation off zero takes weeks.

When it's worth it

  • Privacy. Customer email data never leaves your boxes. Genuinely useful for strict GDPR readings.
  • Volume. Past 100,000 messages a month a $40 VPS undercuts every transactional service.
  • Control. Your rules, your limits, no account suspensions for "policy violations" a robot decided.

When it isn't

  • No sysadmin background. A misconfigured mail server is worse than shared hosting — at least the host's IP has some reputation.
  • Fresh IP. A brand-new sending IP is invisible to receivers. Reputation builds over weeks. Transactional services hand you established reputation on day one.
  • No PTR record. Without reverse DNS most receivers reject your mail outright.
  • Maintenance. Patches, certificates, blocklist monitoring, log review — ongoing, not optional.

What we'd pick

Mailcow: Docker-based, webmail, antispam, antivirus, autodiscover all in the box. 4GB+ RAM. This is what we run.

Mail-in-a-Box: All-in-one on a dedicated Ubuntu host. Simpler, but it takes over the machine.

iRedMail: Traditional Postfix + Dovecot. Most flexible, lightest, most manual.

Send your own business email through a new self-hosted server for three months before you route a single customer order through it. Build reputation slowly. Keep a transactional service wired up as fallback the whole time.

The email types PrestaShop sends

Must reach the inbox immediately

  • Order confirmation (order_conf). The one that drives chargebacks and bad reviews when it doesn't arrive. Protect this above all others.
  • Payment confirmation (payment). Customers are nervous until they see it.
  • Password reset (password_query). Time-sensitive. Ten minutes late and the customer has already given up.
  • Account creation (account). First impression of your shop in their inbox.

Should arrive promptly

  • Shipping notification (shipping). Tracking number lives here.
  • Order status updates (order_changed). Processing, shipped, delivered.
  • Invoice and refund. Critical for B2B, reassuring for everyone.
Keep transactional mail and newsletters on different domains. Order emails go out from your primary domain; newsletters from a subdomain like news@mail.yourstore.com. The day a newsletter triggers spam complaints, it doesn't take your order confirmations down with it.

Templates live in mails/{iso_code}/. Each one has an HTML and a plain-text version. Keep both — a missing .txt is a spam signal on its own, and we've seen translation modules silently delete them during sync.

Hosting and email

What shared hosting can't fix

  • Shared IP reputation. You share an IP with hundreds of other sites and you cannot control what they send.
  • Sending caps. Typically 100-500/hour, 500-5,000/day. A flash sale eats that in minutes.
  • No dedicated IP. Not on offer at this price point.
  • Limited DNS control. Cheap hosts sometimes won't let you publish a custom DKIM, TXT or PTR record.
  • Outbound port 587 blocked. Yes, this still happens — and it stops you connecting to any transactional service.

What a VPS gives you

  • A dedicated IP with reputation that's yours alone
  • No artificial sending limits
  • PTR (reverse DNS) — non-negotiable for serious deliverability
  • Full DNS control, any mail server you want

Hosting red flags

  • "Unlimited email." Doesn't exist on shared hosting. Marketing copy, nothing more.
  • No DKIM support. Walk away.
  • Port 587 blocked. You can't use any transactional service.
  • Blocklisted IPs. Check at MXToolbox before you sign up, not after.
The best play on shared hosting is to ignore the host's mail entirely. Plug a transactional service into PrestaShop via SMTP. Your shop sends through their established reputation and the shared IP problem stops existing.

What changed in PrestaShop 8 and 9

PS 8 — final Swift Mailer

The last stable Swift Mailer 6.x, with better TLS negotiation, more useful error logs in var/logs/, and outgoing message metadata recorded in ps_mail. CLI test from the console: php bin/console prestashop:mail:test recipient@example.com.

PS 9 — Symfony Mailer

Full replacement of the transport. Key things to know:

  • Distinguishes smtp:// (STARTTLS, port 587) from smtps:// (implicit TLS, port 465). The two are no longer interchangeable.
  • Stricter about the envelope sender matching the From header — some SMTP relays that worked on PS 8 stop accepting mail.
  • Stricter TLS certificate validation. Self-signed certs that limped along on PS 8 will fail.
  • Modules that imported Swift_Message or Swift_SmtpTransport break on PS 9 until the developer updates them.
# PS 9 email via environment variables (advanced)
# .env.local — overrides admin panel settings
MAILER_DSN=smtp://user:password@smtp.example.com:587
MAILER_DSN=smtp://user%40gmail.com:app-pass@smtp.gmail.com:587
# Special chars must be URL-encoded: @ = %40, : = %3A

For local dev only, with a self-signed cert:

# Disable TLS verification (NEVER in production)
MAILER_DSN=smtp://user:pass@host:587?verify_peer=0

Testing and monitoring

Before you launch

mail-tester.com: send one test email to the address they give you, get a score out of 10 with line-by-line issues. Aim for 9+. Free for 3 tests/day. It checks SPF, DKIM, DMARC, blocklists, HTML quality, headers, and link reachability.

MXToolbox: DNS diagnostics. MX records, SPF validity and lookup count, DKIM resolution, DMARC policy, blocklist status. Bookmark it.

Once you're live

Google Postmaster Tools: spam rate, IP reputation, domain reputation, authentication success — all from Gmail's own perspective. Free, needs you to verify the domain.

Read the headers. In Gmail: open message → three dots → "Show original." You want to see:

SPF: PASS with IP 1.2.3.4
DKIM: PASS (signature verified)
DMARC: PASS

Cadence we follow: weekly skim of ps_mail for failures and a glance at DMARC reports. Monthly mail-tester check and blocklist sweep. Re-verify DNS after every change. Test email after every PrestaShop core update — the upgrade scripts have rewritten app/config/parameters.php on us more than once.

Common problems and what to look at first

"Test email works but customers don't get order emails"

  • Smarty error in the template. A broken variable in the order template silently kills the send. Check var/logs/.
  • Missing language template. No mails/{lang_iso}/order_conf.html for the customer's language and PrestaShop sends nothing.
  • SMTP timeout. A 30-line order with images can take long enough to render that slow SMTP servers drop the connection.
  • From-address rejection. Some relays refuse to send unless the From matches the authenticated user.

Rate limiting

Importing 200 orders or sending a newsletter to a thousand customers? Your SMTP server takes the first batch and refuses the rest. Space sends out, check provider caps, or move to a transactional service that queues for you.

Encoding problems (PL, CZ, DE, FR diacritics)

  • Subject line garbled. Your install must be UTF-8 end to end. Subjects encode as RFC 2047.
  • Body garbled. Email template files must be UTF-8 without BOM. Notepad on Windows likes to save as ANSI — use VS Code.
  • Database mismatch. Tables should be utf8mb4. Confirm with SHOW CREATE TABLE ps_product_lang;

Mail blocked after a server migration

  • SPF still points at the old IP
  • DKIM key mismatch because the new host minted a new keypair
  • New IP has zero reputation — warm it gradually over two weeks
  • Port 587 blocked on the new host
  • DNS propagation — give it 24-48 hours after changing records

Contact form messages not arriving

Some modules set the customer's email as the From address on the contact form. That fails SPF instantly — your server is not authorised to send as customer@gmail.com. The From should always be your shop's domain, with the customer in Reply-To. We've fixed this on more contact-form modules than we care to count.

Deliverability checklist

Step 1 — foundation

  • ☐ Switch off PHP mail() and onto real SMTP
  • ☐ Create a dedicated sending mailbox (e.g. orders@yourstore.com)
  • ☐ Test send to Gmail and Outlook — both must hit the inbox

Step 2 — DNS authentication

  • ☐ Publish an SPF record — verify it at MXToolbox, under 10 lookups
  • ☐ Enable DKIM and publish the public key
  • ☐ Add a DMARC record at p=none with rua reporting
  • ☐ Open a delivered message and confirm SPF, DKIM, DMARC all show PASS

Step 3 — quality

  • ☐ Score 9+ on mail-tester.com
  • ☐ Sending IP not on any blocklist
  • ☐ Templates exist for every language, both HTML and plain text

Step 4 — real-world test

  • ☐ Place a test order — confirmation hits the inbox in seconds
  • ☐ Walk it through every order state — each status email arrives
  • ☐ Test password reset, account creation, contact form

Step 5 — monitor

  • ☐ Register at Google Postmaster Tools
  • ☐ Set up DMARC report processing
  • ☐ Move DMARC to p=quarantine after 2-4 weeks, then to p=reject
  • ☐ Monthly deliverability check on the calendar

Step 6 — advanced

  • ☐ Move to a transactional service once you hit hosting limits
  • ☐ Split transactional and marketing across separate domains
  • ☐ PTR record set if you're on VPS/dedicated
  • ☐ Bounce handling wired up

Every layer (SMTP, SPF, DKIM, DMARC, clean templates, a reputable sending IP) stacks on the previous ones. Skip one and the whole structure weakens. Work through the checklist in order, retest after each change, and your order confirmations will reach the inbox where they belong. For wider diagnostics see our troubleshooting guide.

Related reading

Loading...
Back to top