Magento 2 SMTP: Ditch PHP mail() and Double Your Deliverability
Out of the box Magento 2 uses PHP mail(), which is a deliverability disaster. Here is how to switch to a proper SMTP setup and what to expect.
Magento 2 still ships with PHP mail() as the default transport, twenty years after that pattern stopped being acceptable. The result is predictable: order confirmations land in spam, password resets never arrive, abandoned-cart emails get filtered, and the merchant blames the platform. The fix is the same as for every PHP app — a real SMTP transport with proper authentication — but Magento's configuration system makes it less obvious than it should be.
This article walks through the deliverability switch for Magento 2.4+: module selection, configuration, transactional vs marketing separation, and the specific Magento gotchas that bite even experienced developers.
Why mail() Is The Problem
PHP mail() hands the message to the local MTA (usually sendmail or postfix) running on the web server. That MTA then sends from the web server's IP, which is typically:
- Not authorised by your domain's SPF.
- Cannot be signed with DKIM because the key is not on the web server.
- Shares an IP with many other shop instances, killing reputation.
- Has no reverse DNS matching your sending domain.
Even the best email content cannot recover from a transport like that.
The Module Landscape
Magento 2 needs a community or commercial module to switch transport. The main options:
| Module | License | Maintained | OAuth |
|---|---|---|---|
| Mageplaza SMTP | Free | Yes | Limited |
| MagePal Custom SMTP | Free | Yes | No |
| Mageworx SMTP | Commercial | Yes | Yes |
| Built-in (2.4.7+) | Free | Yes | No |
Magento 2.4.7 added a native SMTP option in core. If you can update to 2.4.7+, use it. Otherwise Mageplaza or MagePal are the safe community choices.
Built-In SMTP Configuration (2.4.7+)
Navigate to Stores → Configuration → Advanced → System → Mail Sending Settings.
- Transport: SMTP
- Host:
smtp.targetsmtp.it - Port: 587
- Authentication: Login
- SSL: TLS
- User: your SMTP username
- Password: your SMTP password
Save, then run bin/magento cache:flush.
Per-Store Senders
Magento has five "Store Email Addresses" (General, Sales, Customer Support, Custom1, Custom2). All five must use a domain you authenticate. If your "General Contact" is set to info@gmail.com while your domain is shop.example.com, DMARC fails on every general email.
Fix:
- General Contact:
contact@shop.example.com - Sales:
orders@shop.example.com - Customer Support:
support@shop.example.com
Then publish SPF/DKIM/DMARC for shop.example.com.
DNS Prerequisites
; SPF
shop.example.com. IN TXT "v=spf1 include:_spf.targetsmtp.it -all"
; DKIM (key from your provider)
ts1._domainkey.shop.example.com. IN TXT "v=DKIM1; k=rsa; p=MIIBI..."
; DMARC
_dmarc.shop.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com; pct=100"⚠️ Warning: Magento sends many different message types (order confirm, shipment, password reset, newsletter). All must align under the same SPF/DKIM. Test each flow before going live.
Separating Transactional from Marketing
Magento newsletters and abandoned-cart campaigns have different deliverability profiles than order confirmations. Best practice: send them through different credentials so reputation is isolated.
In Magento, override the "Newsletter" sender via the same Configuration screen, but choose a different SMTP credential (e.g. marketing-smtp.targetsmtp.it vs tx-smtp.targetsmtp.it). With Mageworx or Mageplaza this is in the UI; with the built-in you may need to override at the email type level using Magento_Email/etc/email_templates.xml.
The Most Common Gotchas
1. Bracketed sender
Magento sometimes formats From as "Acme Shop" <contact@shop.example.com>. Some SMTP relays strip the display name. Set "Sender Name" without exotic characters.
2. Inline cron
Magento's order confirmation is queued and sent via cron. If cron is not running, no email ever leaves. Verify crontab -l has the Magento cron lines.
php /var/www/magento/bin/magento cron:run3. Template variable in subject
Templates reference variables like {{var order.increment_id}}. A missing variable renders to "Order # has shipped" — looks like a bug to the customer. Always test templates with a real order.
4. PDF attachments
Order confirmations with PDF invoices attached blow past 1 MB easily. Many SMTP relays cap at 25 MB; double-check the post-encoding size, not the file size.
5. Disable mail logs that catch passwords
Magento can log every outbound email. If logs include the full body, password reset tokens end up on disk. Either disable body logging or rotate logs aggressively.
Test Procedure
- Place a test order through the storefront.
- Check
var/log/system.logfor SMTP errors. - Confirm the order email arrives.
- Check headers:
spf=pass,dkim=pass,dmarc=pass. - Trigger password reset, shipment, invoice, refund — all five.
- Send a newsletter to a seed list.
- Verify Postmaster Tools picks up the volume after 48h.
Measuring the Win
Typical results moving from PHP mail() to a properly configured SMTP transport with aligned authentication:
- Inbox placement: from 40-60% to 90-98%.
- Spam folder: from 30-50% to 1-3%.
- Hard bounces: drop because spam-folder messages no longer rot.
- Conversion on transactional flows: lifts 10-30% (people actually see receipts).
Closing
Switching Magento off PHP mail() is the single highest-leverage deliverability change an e-commerce stack can make. The work is half a day; the payoff is permanent. Target SMTP's Magento integration handles the configuration, per-email-type credential split and DNS verification end-to-end. The Send-Time Firewall enforces the recipient allowlist and idempotency at send-time, so a Magento bug or a misconfigured automation does not turn into a thousand duplicate order confirmations.