Het symptoom: stilletjes mislukken
Je stuurt een contactformulier in en er komt niets binnen. Je vraagt een wachtwoord-reset aan en de inbox blijft leeg. Een WooCommerce-bestelling gaat door (als dat specifiek jouw symptoom is, zie WooCommerce-bestelmails worden niet verstuurd), maar de klant krijgt geen bevestiging. Geen foutmelding, geen waarschuwing in de admin, gewoon stilte. Juist die stilte maakt dit probleem zo vervelend: WordPress rapporteert succes terwijl er in werkelijkheid helemaal niets bij de ontvanger is aangekomen.
Wat "niet versturen" eigenlijk betekent
WordPress verstuurt mail via de wp_mail()-functie. Die geeft het bericht op een Linux-server door aan de PHP-functie mail(), die het op zijn beurt doorgeeft aan een lokale sendmail-compatibele binary (postfix, exim, sendmail). De PHP-documentatie zegt het zonder omhaal: "Just because the mail was accepted for delivery, it does NOT mean the mail will actually reach the intended destination." Met andere woorden: wp_mail() kan true teruggeven, je host kan het bericht accepteren, en de ontvangende mailserver kan het daarna gewoon laten vallen zonder iemand in te lichten.
"Niet versturen" valt daarom bijna altijd in één van deze drie faallagen:
- WordPress bouwt het bericht niet eens of geeft het niet door. Een plugin onderschept de aanroep, het ontvangstadres klopt niet, of een fatale PHP-fout stopt het script voordat de mailregel wordt bereikt.
- De host accepteert het bericht maar levert het nooit af. PHP
mail()staat uit, de lokale MTA is niet ingesteld, of uitgaande poort 25 is geblokkeerd. - De ontvangende mailserver weigert het of gooit het stilletjes in spam. SPF, DKIM of DMARC faalt, het verzend-IP staat op een blocklist, of het From-adres is vervalst.
Welke fix werkt, hangt af van welke laag faalt. De diagnose hieronder vertelt je welke.
Veelvoorkomende oorzaken, op volgorde van waarschijnlijkheid
Op basis van wat ik bij shared en managed WordPress hosting in de praktijk tegenkom, is de ruwe volgorde:
- De host heeft
mail()uitgezet of sterk gelimiteerd, of stuurt uitgaande mail naar een lokale mailbox die je nooit leest. - Het default From-adres is
wordpress@jouwsite.nl, dat faalt op DMARC-alignment bij strenge providers zoals Gmail en Outlook en wordt stilletjes in spam gegooid. - SPF-, DKIM- of DMARC-records ontbreken of kloppen niet voor het verzendende domein.
- Je contactformulier-plugin gebruikt het adres van de bezoeker als From-header. Vrijwel elke provider weigert dat inmiddels als spoofing.
- Een security-plugin of SMTP-plugin is verkeerd geconfigureerd en blokkeert uitgaande mail stilletjes.
- Er zit een kritieke PHP-fout op de pagina die de mail zou triggeren, dus
wp_mail()wordt niet eens bereikt. - De site heeft een database-connectiefout, waardoor transactionele mails nooit in de queue komen.
Diagnose: achterhaal welke laag faalt
Voor je iets gaat veranderen, doe je deze drie checks op volgorde. Alle drie zijn niet-destructief.
Stap 1: stuur een testmail en leg het resultaat vast
Installeer Check & Log Email (gratis, 100.000+ actieve installaties per april 2026). Die plugin logt elke wp_mail()-aanroep, registreert of PHP succes of een fout teruggaf en bewaart de headers, body en eventuele foutmelding. Voor dit probleem is het gewoon de nuttigste tool die er is, omdat hij je direct vertelt of het bericht überhaupt WordPress heeft verlaten.
Ga naar Check & Log Email > Status en stuur een testmail naar een adres op een ander domein dan je WordPress-site. Kijk daarna in het log.
Je weet dat het werkt als: het logregel groen is en de testmail daadwerkelijk binnenkomt in de inbox waar je hem naartoe hebt gestuurd. Staat er groen maar komt er niks aan, dan zit de fout op laag 2 of 3 (hosting of DNS). Is het rood of "failed", dan zit de fout op laag 1 (WordPress).
Stap 2: vang de echte fout met wp_mail_failed
Als Check & Log Email een fout toont maar geen bruikbare melding geeft, haak dan in op de wp_mail_failed-action om de onderliggende PHPMailer-exception te zien. Deze action zit sinds WordPress 4.4 in core en wordt afgevuurd zodra een PHPMailer-exception wordt afgevangen.
Maak een bestand log-mail-errors.php aan in wp-content/mu-plugins/ via de bestandsbeheerder in je hostingpanel (of download de map via SFTP, maak het bestand lokaal aan en upload het). Bestaat de map mu-plugins nog niet, maak die dan eerst aan. Plak dit in het bestand:
<?php
// Logt elke wp_mail()-fout naar wp-content/debug.log
add_action( 'wp_mail_failed', function ( WP_Error $error ) {
error_log( 'wp_mail_failed: ' . $error->get_error_message() );
error_log( print_r( $error->get_error_data(), true ) );
} );
Trigger daarna opnieuw een mail (verstuur het contactformulier nog eens, vraag een wachtwoord-reset aan). Open vervolgens wp-content/debug.log via de bestandsbeheerder in je hostingpanel (of download het bestand via SFTP). Je ziet nu de tekst van de PHPMailer-exception, die meestal de exacte reden noemt: SMTP authentication failed, recipient rejected, connection refused, enzovoort.
Je weet dat het werkt als: er in debug.log een regel staat die begint met wp_mail_failed: en een concrete foutmelding bevat. Staat er geen regel, dan wordt wp_mail() gewoon helemaal niet aangeroepen. Dat wijst op een kritieke fout of een plugin-filter dat de aanroep opslokt.
Stap 3: controleer of de host het bericht echt heeft geaccepteerd
Lijken laag 1 en 2 gezond maar komt de mail alsnog niet aan bij de ontvanger, kijk dan in het uitgaande mail-log van je host. Bij cPanel heet dat Email > Track Delivery. Bij DirectAdmin is het E-mail Manager > Mailqueue Administration. Bij managed WordPress hosts zit het meestal onder een "Mail" of "Email log"-paneel in het dashboard.
Je zoekt een regel met je afzender, je ontvanger en een status: "sent", "deferred" of "bounced". Bij een "bounced"-regel staat er bijna altijd de exacte afwijzing van de ontvangende server ("550 5.7.1 SPF check failed", "DMARC policy", "Recipient address rejected").
Je weet dat het werkt als: je het host-log kunt openen en precies ziet wat er met jouw testbericht is gebeurd. Is het host-log leeg terwijl Check & Log Email groen was, dan heeft de host het bericht stilletjes weggegooid voordat het ooit een echte MTA raakte. Sla door naar de hosting-oplossingen hieronder.
Oplossingen per laag
Laag 1: WordPress verstuurt het bericht niet
Oorzaak: een plugin of filter onderschept wp_mail().
Schakel elke security-, SMTP- of anti-spam-plugin die je hebt tijdelijk uit. Werkt de mail dan wel, zet ze dan één voor één weer aan tot de boosdoener zich meldt. Wat ik het vaakst zie: verkeerd geconfigureerde SMTP-plugins die naar een dode mailserver wijzen, en security-plugins die uitgaande mail standaard blokkeren.
Je weet dat het werkt als: een nieuwe testmail via Check & Log Email aankomt in de inbox van de ontvanger, met alle mail-gerelateerde plugins van derden uitgeschakeld.
Oorzaak: de contactformulier-plugin misbruikt de From-header.
Open je contactformulier-plugin (Contact Form 7, Gravity Forms, Fluent Forms) en kijk naar de mailinstellingen van het formulier. Het From-adres moet op een domein staan dat jij beheert, bijvoorbeeld formulieren@jouwsite.nl, en dus niet het adres van de bezoeker. Zet het adres van de bezoeker in Reply-To. Zonder die aanpassing faalt elke moderne ontvanger op DMARC-alignment en gaat de mail in spam of wordt hij geweigerd.
Je weet dat het werkt als: een testinzending een regel in Check & Log Email oplevert waarvan het From-adres op je eigen domein staat, en de mail aankomt.
Oorzaak: een kritieke fout op de pagina die de mail triggert.
Laad de pagina die de e-mail zou moeten triggeren (het contactformulier, het wachtwoord-reset-formulier, de WooCommerce-checkout) en open wp-content/debug.log via de bestandsbeheerder in je hostingpanel om te kijken of er fatale fouten gelogd worden. Geeft die pagina stilletjes een 500, bekijk dan er is een kritieke fout op deze website.
Je weet dat het werkt als: de pagina schoon laadt, het debug-log geen fatale fouten tijdens die request toont, en een nieuwe inzending een regel in het mail-log oplevert.
Laag 2: de host levert het bericht niet af
Oorzaak: de host heeft PHP mail() uitgezet of sterk gelimiteerd.
Veel shared hosts zetten PHP mail() uit vanwege misbruik of beperken het tot een paar tientallen berichten per uur. Open een supportticket en stel de vraag direct: "Staat PHP mail() aan op mijn account, en wat is de limiet per uur voor uitgaande mail?" Staat het uit, dan moet je over op SMTP (zie verderop). Is het gelimiteerd en loop je tegen de limiet aan, dan is de fix hetzelfde.
Je weet dat het werkt als: de host bevestigt dat mail() onbeperkt aanstaat, of je bent overgegaan op SMTP en je testmail komt aan.
Oorzaak: mailrouting staat op "lokaal" terwijl je extern mail gebruikt. Wijst de MX-record van je domein naar Google Workspace, Microsoft 365 of een andere externe mailprovider, dan moet de mailrouting voor dat domein in je hostingpanel op Remote staan, niet op Local. Staat het op lokaal, dan probeert de host af te leveren aan een mailbox op z'n eigen server die daar niet bestaat, en verdwijnt het bericht in het niets. Bij cPanel vind je dit onder Email Routing. Bij DirectAdmin onder MX Records > Use this server to handle my emails: No.
Je weet dat het werkt als: het host-log laat zien dat het bericht is doorgegeven aan een externe smarthost (of de ontvanger als remote address verschijnt) en de testmail komt aan.
Oorzaak: het gedeelde uitgaande IP staat op een blocklist. Pak het IP-adres uit de uitgaande mailregel in je host-log en check het tegen MultiRBL of een vergelijkbare aggregator. Zie je hits op Spamhaus, SORBS of Barracuda, dan is de schoonste oplossing niet om met de blocklist in gevecht te gaan: stap over op geauthenticeerde SMTP via een transactionele verzender (zie Laag 3), zodat je deliverability niet langer afhangt van dat gedeelde IP.
Je weet dat het werkt als: uitgaande mail via de transactionele verzender loopt, het uitgaande host-IP niet meer in het bericht-pad zit, en de testmail in de inbox aankomt.
Laag 3: de ontvangende mailserver weigert of junkt het bericht
Dit is waar moderne WordPress-mailproblemen meestal echt zitten. Sinds de bulk sender requirements van Google en Yahoo in februari 2024 van kracht werden, ligt de lat voor acceptatie bij Gmail (en Outlook, en Yahoo) een stuk hoger dan vroeger. Zelfs voor kleine verzenders is de praktijk-ondergrens nu: stuur via geauthenticeerde SMTP, met SPF, DKIM en DMARC die aligned zijn op je verzendende domein.
De fix is tweeledig: route de mail via een geauthenticeerde SMTP-dienst en voeg daarna de bijbehorende DNS-records toe.
Stap 1: kies een SMTP-dienst. Gebruik een dienst die je uitgaande mail met DKIM ondertekent voor jouw domein en een bounce-dashboard biedt. Opties die in april 2026 gangbaar zijn: Postmark, Mailgun, SendGrid, Amazon SES, Brevo (voorheen Sendinblue). Voor laagvolume transactionele mail (formulier-meldingen, wachtwoord-resets, bestelbevestigingen) heeft bijna elke dienst een gratis laag van een paar honderd berichten per dag.
Stap 2: installeer een SMTP-plugin en configureer hem.
WP Mail SMTP, FluentSMTP en Post SMTP doen feitelijk hetzelfde: ze haken in op phpmailer_init om de standaardverzending van WordPress te vervangen door een geauthenticeerde SMTP-verbinding. De betreffende action is gedocumenteerd als phpmailer_init. Kies er één, vul de host, poort (meestal 587 met STARTTLS of 465 met implicit TLS), gebruikersnaam en wachtwoord van je SMTP-dienst in, en zet het From-adres op een echt adres op je eigen domein. Sla op en stuur een testmail.
Stap 3: voeg de DNS-records toe die je SMTP-dienst je aanreikt. Elke SMTP-dienst geeft je de exacte SPF-, DKIM- en soms DMARC-records die je in je DNS-zone moet zetten. Voeg die toe als TXT-records bij je DNS-provider. Ter context:
- SPF (RFC 7208) bepaalt welke mailservers namens jouw domein mogen versturen.
- DKIM (RFC 6376) laat de verzender het bericht cryptografisch ondertekenen, zodat de ontvanger kan verifiëren dat het onderweg niet is gewijzigd.
- DMARC (RFC 7489) bepaalt wat de ontvanger moet doen als SPF of DKIM faalt, en vereist dat het domein in de From-header aligned is met één van beide.
Een minimale DMARC-record om mee te beginnen, terwijl je controleert of alles aligned is:
_dmarc.jouwsite.nl. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@jouwsite.nl"
p=none betekent "alleen monitoren, niet afwijzen". Als je een week of twee aan DMARC-rapporten hebt bekeken en zeker weet dat je legitieme mail slaagt, kun je de policy verhogen naar p=quarantine en uiteindelijk naar p=reject.
Je weet dat alle drie de stappen werken als: een testmail van je WordPress-site aankomt in een Gmail-inbox, je klikt op "Show original", en je in de Authentication-Results-header ziet staan: SPF: PASS, DKIM: PASS en DMARC: PASS. Staat er bij één van die drie FAIL of NEUTRAL, dan klopt de bijbehorende record niet en moet je die bijstellen voordat de mail betrouwbaar wordt geaccepteerd.
Nog één oorzaak waar veel mensen op stranden: het default From-adres
Het standaard From-adres van WordPress is wordpress@<je hostnaam>, gebouwd vanuit $_SERVER['SERVER_NAME'] in wp-includes/pluggable.php. Draait je site op www.jouwsite.nl en overschrijf je de From-header niet, dan gaat elke door WordPress gegenereerde mail de deur uit als wordpress@jouwsite.nl. Daar gaan twee dingen mis:
- Die mailbox bestaat niet, dus elke reply of bounce verdwijnt.
- Gebruik je een aparte mailprovider voor
@jouwsite.nl, dan heeft je SMTP-pad waarschijnlijk niet de rechten om als@jouwsite.nlte versturen en faalt DMARC.
De fix is simpel: zet een expliciet, echt From-adres in je SMTP-plugin (of via de filters wp_mail_from en wp_mail_from_name), en wijs het aan een mailbox die je ook daadwerkelijk in de gaten houdt.
Je weet dat het werkt als: Check & Log Email het nieuwe From-adres toont op elke uitgaande mail, replies op dat adres ook echt binnenkomen, en DMARC slaagt.
Wanneer je moet escaleren
Heb je alle drie de lagen doorlopen en lukt het nog steeds niet om mail betrouwbaar weg te krijgen, vraag dan je host om hulp. Verzamel voordat je het ticket opent:
- Je PHP-versie (WordPress > Gereedschap > Status site > Info, of
php -vals je shell-toegang hebt). - Je hostingpakket en providernaam.
- De exacte foutmelding uit
wp-content/debug.log(de regel die begint metwp_mail_failed:). - De headers en status van één gefaalde testmail uit het log van Check & Log Email.
- De relevante regels uit het uitgaande mail-log van je host voor dat testbericht.
- De volledige lijst actieve plugins (Gereedschap > Status site > Info > Actieve plugins).
- Je huidige SPF-, DKIM- en DMARC-records zoals ze in DNS staan (zoek ze op met een gratis tool als MXToolbox, of gebruik
dig TXT jouwsite.nlendig TXT _dmarc.jouwsite.nlals je shell-toegang hebt). - Het From-adres waarmee WordPress nu verstuurt, en de MX-records van hetzelfde domein.
Met dat pakket erbij lost een support-engineer dit in een paar minuten op. Zonder, wordt het een ticket van dagen heen en weer.
Gaat het specifiek om wachtwoord-reset-mails die niet aankomen, dan is de diagnose identiek aan hierboven, maar de bredere gebruikerscontext staat in wachtwoord reset werkt niet in WordPress.
Hoe voorkom je dat het terugkomt
- Stuur alle WordPress-mail vanaf dag één via een geauthenticeerde SMTP-dienst. Bouw in 2026 geen shared hosting meer op PHP
mail(). - Houd je SPF-, DKIM- en DMARC-records in version control of documenteer ze in elk geval buiten je DNS, zodat je ze na een registrarwissel kunt reproduceren.
- Zet DMARC eerst op
p=noneen verhoog pas naarp=quarantineofp=rejectna een paar weken schone rapporten. - Hou je verzendvolume maandelijks in de gaten. Kom je boven de drempel van 5.000 berichten per dag voor bulk senders richting Gmail, dan gelden strengere regels (one-click unsubscribe, spam-klachtpercentage onder 0,30%).
- Laat Check & Log Email ook op een gezonde site staan, met een bewaartermijn van ongeveer 30 dagen. De eerste keer dat er iets misgaat, heb je dan gewoon een log om te lezen in plaats van te moeten gokken.