E-commerce7 min read

OpenCart + PHP mail(): the deliverability wall

OpenCart 3 and 4 ship a working transactional pipeline that depends on PHP's mail() function. On shared hosting that is almost guaranteed to fail. Here is the SMTP + DNS path that fixes it for good.

OpenCart admins discover the deliverability problem the same way everyone else does — a customer messages asking for their order details, and you realise the confirmation never arrived. Except OpenCart has one extra quirk: the default configuration in System → Settings → Mail is set to "Mail" (PHP mail()) rather than SMTP. Most admins never change it.

The fix is configurable inside OpenCart itself — no plugins required for basic SMTP — but the UI is unhelpful, and the DNS side of the equation is ignored by every OpenCart tutorial that shows only the admin panel.

Two switches, four DNS records

Change Mail Engine to SMTP in OpenCart admin. Point at an authenticated relay. Then publish SPF, DKIM, DMARC, and a return-path CNAME for the relay. That is the whole fix.

Why PHP mail() fails on OpenCart hosting

  • Shared IP reputation: OpenCart runs on LAMP. LAMP runs on shared hosts. Shared hosts share IPs. Your order confirmation competes with every other tenant's newsletter.
  • No DKIM: PHP mail() does not sign. The few hosts with cPanel DKIM at the MTA layer sign with the wrong selector and wrong domain, which is worse than not signing.
  • Envelope mismatch: the store'semail setting in admin controls the header From only. The envelope MAIL FROM is whatever the local sendmail decides, usually the cPanel username.
  • No visibility: PHP mail() returns true or false. If false, OpenCart logs a generic error. If true, the message could still be dropped silently downstream.

Switch OpenCart to SMTP

System → Settings → Store → Mail tab. Change Mail Engine from "Mail" to "SMTP". Then fill in the relay details.

SMTP settings for common relays

# Brevo (ex-Sendinblue) — free 300/day
SMTP Hostname: smtp-relay.brevo.com
SMTP Username: your_brevo_login@yourstore.com
SMTP Password: SMTP key from Brevo dashboard (not your password)
SMTP Port: 587
SMTP Security: TLS

# SendGrid
SMTP Hostname: smtp.sendgrid.net
SMTP Username: apikey
SMTP Password: full SG API key
SMTP Port: 587
SMTP Security: TLS

# Amazon SES (eu-west-1 example)
SMTP Hostname: email-smtp.eu-west-1.amazonaws.com
SMTP Username: SES SMTP credentials username
SMTP Password: SES SMTP credentials password
SMTP Port: 587
SMTP Security: TLS
Mail Timeout

OpenCart sets SMTP Timeout to 5 seconds by default. On transactional paths that is fine. If the relay occasionally takes longer to handshake, bump to 15. Longer than that and you are papering over a relay problem.

DNS: SPF, DKIM, DMARC, return-path

OpenCart's admin panel does not show you what DNS records to add. The relay dashboard does. Take those records and publish them at your domain registrar.

; example for Brevo, apex = yourstore.com
yourstore.com.             TXT   "v=spf1 include:spf.brevo.com ~all"
mail._domainkey.yourstore.com TXT "k=rsa; p=<brevo_provided_key>"
_dmarc.yourstore.com       TXT   "v=DMARC1; p=none; rua=mailto:dmarc@yourstore.com"

; return-path alignment (Brevo custom envelope)
bounce.yourstore.com       CNAME ob.sendibm3.com.

Test every order status

OpenCart fires a different template for each order status. Testing only "order placed" misses that "complete" might have broken HTML or a stale attachment path.

  1. Run a real test order with a seed mailbox as customer email.
  2. Move the order through Pending → Processing → Complete, checking each status email.
  3. Trigger a password reset from the customer account page.
  4. Trigger a return request.

Template hygiene

  • OpenCart templates live atcatalog/view/theme/<theme>/template/mail/. Most themes ship a heavy HTML layout — strip promotional blocks.
  • Ensure a text/plain alternative exists. OpenCart generates one automatically if you provide plain-text template siblings, not otherwise.
  • Logo image under 10 KB, no banners, no product-recommendation grids in confirmation emails.
  • Reply-to set to a monitored mailbox, not a no-reply address.
Seed-test OpenCart before every update

After every template change or plugin install, run a seed test across 20+ providers. Catch Promotions-tab drift and DMARC alignment breaks before customers do.

→ Run Free Test

FAQ

Does OpenCart 4 handle SMTP differently from OpenCart 3?

The UI moved slightly in 4 and it now supports OAuth for Google and Microsoft, but the underlying transport is the same Zend-based mailer. The fix is identical.

Can I keep PHP mail() if my host signs DKIM at the MTA?

Technically yes, but practically no. Host-level DKIM signs for the hosting provider's domain, not yours, so DMARC fails alignment. Use SMTP to a relay on your own domain.

Is Gmail SMTP a good choice for OpenCart?

Fine for very small stores — 500 messages/day limit. For anything beyond that, use a transactional relay. Gmail will throttle and the error surfaces as silent failure.

Why is my admin new-order notification still missing?

Admin notifications use the same mailer but a different template. If the admin email is on a corporate filter (Microsoft 365 with aggressive junking), whitelist the relay's IP range in the tenant-level spam policy.
Related reading

Check your deliverability across 20+ providers

Gmail, Outlook, Yahoo, Mail.ru, Yandex, GMX, ProtonMail and more. Real inbox screenshots, SPF/DKIM/DMARC, spam engine verdicts. Free, no signup.

Run Free Test →

Unlimited tests · 20+ seed mailboxes · Live results · No account required