{"id":360907,"date":"2026-09-10T07:42:18","date_gmt":"2026-09-10T07:42:18","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/wonderful-smtp-mailer-and-log\/"},"modified":"2026-09-10T07:41:56","modified_gmt":"2026-09-10T07:41:56","slug":"wonderful-smtp-mailer-and-log","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/wonderful-smtp-mailer-and-log\/","author":23357214,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.1","stable_tag":"1.0.1","tested":"7.1","requires":"6.2","requires_php":"7.4","requires_plugins":null,"header_name":"Wonderful SMTP Mailer and Log","header_author":"Wonderful Plugins","header_description":"Simple, bloatware-free SMTP email plugin: sends by SMTP, logs the result, resends failures. Minimal and secure on purpose, and it will stay minimal.","assets_banners_color":"","last_updated":"2026-09-10 07:41:56","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/wonderfulplugins.eu\/wonderful-smtp-mailer-and-log","header_author_uri":"https:\/\/wonderfulplugins.eu","rating":0,"author_block_rating":0,"active_installs":20,"downloads":34,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.1":{"tag":"1.0.1","author":"wonderfulplugins","date":"2026-09-10 07:41:56","revision":3689488}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3689488,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3689488,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":[],"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.1"],"block_files":[],"assets_screenshots":{"screenshot-1-de.jpg":{"filename":"screenshot-1-de.jpg","revision":3689488,"resolution":"1","location":"assets","locale":"de","width":1440,"height":1250},"screenshot-1.jpg":{"filename":"screenshot-1.jpg","revision":3689488,"resolution":"1","location":"assets","locale":"","width":1440,"height":1250},"screenshot-2-de.jpg":{"filename":"screenshot-2-de.jpg","revision":3689488,"resolution":"2","location":"assets","locale":"de","width":1440,"height":1750},"screenshot-2.jpg":{"filename":"screenshot-2.jpg","revision":3689488,"resolution":"2","location":"assets","locale":"","width":1440,"height":1750},"screenshot-3-de.jpg":{"filename":"screenshot-3-de.jpg","revision":3689488,"resolution":"3","location":"assets","locale":"de","width":1440,"height":1350},"screenshot-3.jpg":{"filename":"screenshot-3.jpg","revision":3689488,"resolution":"3","location":"assets","locale":"","width":1440,"height":1350},"screenshot-4-de.jpg":{"filename":"screenshot-4-de.jpg","revision":3689488,"resolution":"4","location":"assets","locale":"de","width":1440,"height":1150},"screenshot-4.jpg":{"filename":"screenshot-4.jpg","revision":3689488,"resolution":"4","location":"assets","locale":"","width":1440,"height":1150},"screenshot-5-de.jpg":{"filename":"screenshot-5-de.jpg","revision":3689488,"resolution":"5","location":"assets","locale":"de","width":1440,"height":1150},"screenshot-5.jpg":{"filename":"screenshot-5.jpg","revision":3689488,"resolution":"5","location":"assets","locale":"","width":1440,"height":1150},"screenshot-6-de.jpg":{"filename":"screenshot-6-de.jpg","revision":3689488,"resolution":"6","location":"assets","locale":"de","width":1440,"height":1150},"screenshot-6.jpg":{"filename":"screenshot-6.jpg","revision":3689488,"resolution":"6","location":"assets","locale":"","width":1440,"height":1150}},"screenshots":{"1":"The dashboard: delivery counts, active mode, and every setting with its\nsource.","2":"SMTP settings, with every value optionally pinned from wp-config.php.","3":"The testing screen: connection check and test message, both showing the raw\nSMTP conversation.","4":"The email log with delivery counts, the date filter and the resend action.","5":"A logged message opened in place, without leaving the list: the server's\nresponse, the headers, the stored attachment and the body a resend would\ndeliver.","6":"A message whose stored attachment has expired, warning before the resend."}},"plugin_section":[],"plugin_tags":[267,908,450,6696,15439],"plugin_category":[41],"plugin_contributors":[247385],"plugin_business_model":[],"class_list":["post-360907","plugin","type-plugin","status-publish","hentry","plugin_tags-email","plugin_tags-log","plugin_tags-mail","plugin_tags-smtp","plugin_tags-webhook","plugin_category-communication","plugin_contributors-wonderfulplugins","plugin_committers-wonderfulplugins"],"banners":[],"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/wonderful-smtp-mailer-and-log\/assets\/icon-128x128.png?rev=3689488","icon_2x":"https:\/\/ps.w.org\/wonderful-smtp-mailer-and-log\/assets\/icon-256x256.png?rev=3689488","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/wonderful-smtp-mailer-and-log\/assets\/screenshot-1.jpg?rev=3689488","caption":"The dashboard: delivery counts, active mode, and every setting with its\nsource."},{"src":"https:\/\/ps.w.org\/wonderful-smtp-mailer-and-log\/assets\/screenshot-2.jpg?rev=3689488","caption":"SMTP settings, with every value optionally pinned from wp-config.php."},{"src":"https:\/\/ps.w.org\/wonderful-smtp-mailer-and-log\/assets\/screenshot-3.jpg?rev=3689488","caption":"The testing screen: connection check and test message, both showing the raw\nSMTP conversation."},{"src":"https:\/\/ps.w.org\/wonderful-smtp-mailer-and-log\/assets\/screenshot-4.jpg?rev=3689488","caption":"The email log with delivery counts, the date filter and the resend action."},{"src":"https:\/\/ps.w.org\/wonderful-smtp-mailer-and-log\/assets\/screenshot-5.jpg?rev=3689488","caption":"A logged message opened in place, without leaving the list: the server's\nresponse, the headers, the stored attachment and the body a resend would\ndeliver."},{"src":"https:\/\/ps.w.org\/wonderful-smtp-mailer-and-log\/assets\/screenshot-6.jpg?rev=3689488","caption":"A message whose stored attachment has expired, warning before the resend."}],"raw_content":"<!--section=description-->\n<p>A small SMTP plugin that does three things and nothing else: it sends your mail\nover SMTP, it writes down what happened, and it tells a webhook when a message\nfails.<\/p>\n\n<p>We built it because the SMTP plugin we had relied on for years kept growing.\nMore features, more integrations, more settings \u2014 most of which we simply\ndidn't need. Eventually, that added complexity started causing problems on\nproduction sites.<\/p>\n\n<p>Many alternatives had gone the same way: email logs behind paid tiers, API\nproviders, OAuth flows, deliverability dashboards, upgrade banners, and entire\nmail suites around what should be a simple job.<\/p>\n\n<p>We wanted the opposite: connect to a mail server, send the email, log the\nresult, and stay out of the way.<\/p>\n\n<p>Email is critical infrastructure. Every additional feature is another dependency\nand another potential failure point \u2014 and when mail breaks, customers notice\nimmediately.<\/p>\n\n<p>So we built the slim alternative we wanted ourselves, and we run it in our own\nproduction environment and on our client sites.<\/p>\n\n<p><strong>What it does<\/strong><\/p>\n\n<ul>\n<li>Routes every <code>wp_mail()<\/code> call over your SMTP server \u2014 WooCommerce, contact\nforms, core password resets, all of it, without touching their code.<\/li>\n<li>Host, port, encryption (STARTTLS, SSL\/TLS or none), optional authentication.<\/li>\n<li>Sender address and name, with an explicit switch for whether they override a\nsender another plugin already set.<\/li>\n<li>A <strong>connection check<\/strong> that logs in to your mail server and hangs up without\nsending anything \u2014 the safe way to find out whether the settings are right.<\/li>\n<li>A test message that shows you the <strong>actual SMTP conversation<\/strong> \u2014 when a server\nanswers \"535 5.7.139 Authentication unsuccessful\", you read that line instead\nof guessing.<\/li>\n<li>A detail view for every logged message: the full server response, the headers,\nthe attachments and the message body as source, so you can see exactly what a\nresend would deliver.<\/li>\n<li>An email log: date, recipient, subject, status and the server's response,\nwith its own menu entry rather than another item buried under Settings.<\/li>\n<li>A date range filter, so an entry from six months ago is two clicks away\ninstead of forty pages down.<\/li>\n<li>Full-text search across recipient, subject and message body, scoped to the\nperiod you filtered \u2014 \"find the mail that mentioned invoice 0912\".<\/li>\n<li>Attachments listed on every logged message, downloadable in one click and\nre-attached automatically when you resend.<\/li>\n<li><strong>Attachment storage<\/strong> \u2014 the part most email logs leave out. A log that records\na filename cannot resend the file, and plenty of plugins delete theirs the\nmoment the message is sent. Switch storage on and a copy is kept for as many\ndays as you choose, in a directory that denies web access, so a message resent\nthree weeks later still carries what it was sent with. Off by default, and\nevery copy is deleted again on schedule.<\/li>\n<li>Delivery counts for the filtered period, next to the all-time totals.<\/li>\n<li>A resend button on every logged message, which asks before it sends and lets\nyou correct the address first \u2014 the usual reason to resend is that the\noriginal one was mistyped.<\/li>\n<li>A <strong>log-only mode<\/strong> that records every message and hands none of them to the\nmail server \u2014 the setting a staging site needs so a real customer can never\nreceive anything.<\/li>\n<li>A dashboard as the landing screen: delivery counts for the last seven days,\nthe active delivery mode, and every setting with its current value and where\nit came from \u2014 the database, or a constant your <code>docker-compose<\/code> passed in.<\/li>\n<li>An optional webhook that fires on failure, so Zapier, n8n, Make or your own\nendpoint can raise an alert.<\/li>\n<\/ul>\n\n<p><strong>What it deliberately does not do<\/strong><\/p>\n\n<p>No API providers, no OAuth, no fallback connections, no deliverability score, no\ndashboard widget, no newsletter integration, no pro tier, no advertising for\none, and no upsell notices. If you need those, one of the big plugins will serve\nyou better, and that is a fine outcome.<\/p>\n\n<p><strong>Safety rails<\/strong><\/p>\n\n<ul>\n<li>With no SMTP host configured the plugin stays out of the way entirely and\nWordPress keeps using PHP <code>mail()<\/code> \u2014 installing it cannot take your email\ndown.<\/li>\n<li><p><strong>Every<\/strong> setting can be defined as a constant in <code>wp-config.php<\/code>, following\none mechanical rule: the option name in upper case. That keeps credentials out\nof the database and out of any dump copied to a staging site, and lets a Docker\ncontainer pass them in as environment variables:<\/p>\n\n<p>define( 'WONDERFUL_SMTP_MAILER_AND_LOG_HOST', getenv( 'SMTP_HOST' ) );\n  define( 'WONDERFUL_SMTP_MAILER_AND_LOG_PASSWORD', getenv( 'SMTP_PASSWORD' ) );<\/p>\n\n<p>A defined constant wins over the settings field, and the field is then shown\nread-only so the two cannot silently disagree.<\/p><\/li>\n<li>No runtime dependencies. The plugin uses the PHPMailer that ships with\nWordPress itself \u2014 there is no vendor directory and nothing to keep patched.<\/li>\n<li>The stored password is never written into the HTML of the settings form. A\ntoggle next to the field fetches it on request, so it stays out of the page\nsource, the browser cache and any screenshot until you deliberately ask.<\/li>\n<li>Log-only mode is announced on every admin screen, not just this plugin's own.\nIt is a silent state by design \u2014 <code>wp_mail()<\/code> keeps reporting success \u2014 and the\nperson who needs the warning is the one wondering why a customer never got\ntheir confirmation.<\/li>\n<li>Stored attachments are deleted when the plugin is deactivated, not just when it\nis uninstalled \u2014 switching it off should not leave a folder of customer\ndocuments on the server.<\/li>\n<li>\"Force sender\" is off by default, so plugins that set their own sender on\npurpose keep it.<\/li>\n<li>Resending is a manual button. Nothing retries by itself, so a failing server\ncan never turn into a mail loop.<\/li>\n<\/ul>\n\n<p><strong>How it is built<\/strong><\/p>\n\n<p>Development is test driven, and the suite covers the behaviour that decides\nwhether your mail actually leaves the building: that an unconfigured plugin keeps\nits hands off PHPMailer entirely, that \"none\" really disables TLS instead of\nquietly upgrading, that a sender another plugin set on purpose survives, that a\ncorrupt delivery-mode value falls back to sending rather than silently swallowing\nyour mail, that log-only mode never once reaches the mailer, that the retention\npurge deletes what is past the cutoff and nothing else, and that a webhook fires\nwith the failure details but no credentials.<\/p>\n\n<p>Those tests run together with the WordPress coding standards, a PHP 7.4\ncompatibility lint and WordPress.org's own Plugin Check every single time, before\na release is built at all. An error in any of them stops the release \u2014 the\npipeline refuses, it is not a checklist someone waves through.<\/p>\n\n<p>The tests themselves stay in the repository and are not part of this download.\nNothing ships here that your site does not need at runtime: a small set of PHP\nclasses and four assets, with no vendor directory and no framework.<\/p>\n\n<p>That discipline is also why the feature list is short. Every feature is a promise\nthat has to keep working.<\/p>\n\n<h3>External services<\/h3>\n\n<p>This plugin contacts two kinds of external endpoints, both of which you\nconfigure yourself. It has no vendor backend, sends no telemetry, and phones\nhome nowhere.<\/p>\n\n<p><strong>1. Your SMTP server<\/strong><\/p>\n\n<p>The host you enter in the settings receives your outgoing messages: sender,\nrecipients, subject, body, attachments, and \u2014 if authentication is enabled \u2014 the\nusername and password you configured. This is the entire purpose of the plugin.\nWhich company that server belongs to, and which terms and privacy policy apply,\nis determined by you when you enter the host name. No connection is made until\nyou configure one.<\/p>\n\n<p><strong>2. Your failure webhook (optional, off by default)<\/strong><\/p>\n\n<p>If, and only if, you fill in the webhook field, a JSON request of the form\n    {\"text\": \"...\"} is sent to that URL whenever a message fails. It contains your\nsite URL, the recipient address, the subject and the error the mail server\nreturned. It contains no message body and no credentials. Nothing is sent while\nthe field is empty. The receiving service is one you choose \u2014 Zapier, n8n, Make,\nSlack or your own endpoint \u2014 and its terms and privacy policy apply to what you\nsend it.<\/p>\n\n<p>Message contents and log entries stay in your own database. No data is\ntransmitted to Wonderful Plugins.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install and activate the plugin.<\/li>\n<li>Go to <strong>SMTP Mailer \u2192 Settings<\/strong> in the admin menu.<\/li>\n<li>Enter host, port and encryption for your mail server. Port 587 with STARTTLS\nfits most providers.<\/li>\n<li>If your server requires a login, leave authentication enabled and fill in\nusername and password. To keep the password out of the database, define\n   WONDERFUL_SMTP_MAILER_AND_LOG_PASSWORD in <code>wp-config.php<\/code> instead.<\/li>\n<li>Set the sender address. Most providers reject a sender that differs from the\naccount you authenticate with.<\/li>\n<li>Optionally add a webhook URL for failure alerts.<\/li>\n<li>Go to <strong>SMTP Mailer \u2192 Testing<\/strong> and run the connection check. If it comes\nback green, send a test message from the same screen.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"i%20installed%20it%20but%20configured%20nothing.%20did%20my%20email%20break%3F\"><h3>I installed it but configured nothing. Did my email break?<\/h3><\/dt>\n<dd><p>No. Without an SMTP host the plugin does not touch outgoing mail at all and\nWordPress keeps using PHP <code>mail()<\/code> exactly as before.<\/p><\/dd>\n<dt id=\"what%20is%20the%20difference%20between%20the%20connection%20check%20and%20the%20test%20message%3F\"><h3>What is the difference between the connection check and the test message?<\/h3><\/dt>\n<dd><p>The connection check opens a session with your mail server, negotiates\nencryption, logs in and hangs up. Nothing is sent and nothing is logged, so you\ncan run it as often as you like while you are getting the settings right. The\ntest message actually delivers an email and records it in the log, which also\nproves that logging works.<\/p><\/dd>\n<dt id=\"the%20test%20message%20fails.%20what%20now%3F\"><h3>The test message fails. What now?<\/h3><\/dt>\n<dd><p>Read the SMTP conversation printed underneath the error. It is the unedited\nexchange with your mail server, and the reason is almost always in the last few\nlines \u2014 wrong credentials, a blocked port, or a sender your provider will not\naccept.<\/p><\/dd>\n<dt id=\"where%20are%20my%20credentials%20stored%3F\"><h3>Where are my credentials stored?<\/h3><\/dt>\n<dd><p>In the WordPress options table, unless you define them as constants in\n    wp-config.php, which is what we recommend for production. The password is\nnever echoed back into the settings form.<\/p><\/dd>\n<dt id=\"can%20i%20get%20an%20attachment%20back%20out%20of%20the%20log%3F\"><h3>Can I get an attachment back out of the log?<\/h3><\/dt>\n<dd><p>Yes. Open the message and click the attachment. The download only ever serves a\nfile this site itself attached to that logged email \u2014 the request names a log\nentry and a position in its attachment list, never a path \u2014 and a resend\nre-attaches whatever is still on disk. Files deleted since are marked as gone.<\/p><\/dd>\n<dt id=\"why%20would%20i%20turn%20on%20attachment%20storage%3F\"><h3>Why would I turn on attachment storage?<\/h3><\/dt>\n<dd><p>Because the log records where an attachment <em>was<\/em>, not the file itself. Some\nplugins keep what they send \u2014 the well-known WooCommerce invoice plugins file\ntheir PDFs away and can hand them back later. Plenty of others do not: form\nuploads written to a temporary directory, one-off exports, reports generated for\na single send. Those are gone within the hour, and a resend then goes out without\nthem.<\/p>\n\n<p>With storage on, a copy is kept regardless of what the sending plugin does, for\nas many days as you choose.<\/p>\n\n<p>Copies are off by default because they are customer documents sitting on disk.\nWhen you turn them on they go into a directory that denies web access and carries\nan <code>index.php<\/code>, and each file is stored under a random 32-character name with a\nneutral <code>.bin<\/code> extension \u2014 so nothing there is guessable, and nothing there is\nsomething a web server would execute even if the directory protection were\nbypassed. The original filename lives in the database and is restored on\ndownload. Files over 10 MB are never copied.<\/p>\n\n<p>A daily job deletes copies past the period you set. Setting it to 0 keeps a copy\nfor as long as its log entry lives \u2014 deleting the entry always takes its copies\nwith it, so a file is never left on disk with no record pointing at it.\nDeactivating the plugin deletes them all, and uninstalling removes the\ndirectory. Once a copy is gone the\nmessage shows the attachment struck through as no longer available, and warns you\nbefore you resend rather than quietly sending it short.<\/p><\/dd>\n<dt id=\"does%20the%20log%20store%20the%20message%20body%3F\"><h3>Does the log store the message body?<\/h3><\/dt>\n<dd><p>Yes \u2014 it has to, otherwise the resend button could not work. Log entries live in\nyour own database and are deleted after the retention period you set, 30 days by\ndefault. Set it to 0 to keep everything.<\/p><\/dd>\n<dt id=\"how%20do%20i%20find%20an%20old%20log%20entry%3F\"><h3>How do I find an old log entry?<\/h3><\/dt>\n<dd><p>Open <strong>SMTP Mailer \u2192 Email Log<\/strong> and set the two date fields above the table.\nThe counters at the top follow the filter, so you also get the delivery numbers\nfor exactly the period you picked. Entries older than your retention setting are\ngone for good, so pick that setting with the audit trail you want in mind.<\/p><\/dd>\n<dt id=\"how%20do%20i%20stop%20a%20staging%20site%20from%20mailing%20real%20customers%3F\"><h3>How do I stop a staging site from mailing real customers?<\/h3><\/dt>\n<dd><p>Set <strong>Delivery mode<\/strong> to \"Log only\". Every message is still recorded in full \u2014\nrecipient, subject, headers and body \u2014 and none of them reaches the mail server.\n    wp_mail() still reports success, so plugins that check its return value behave\nnormally. Suppressed messages show up in the log as \"Not sent\" and are not\ncounted as delivered.<\/p><\/dd>\n<dt id=\"does%20anything%20retry%20automatically%3F\"><h3>Does anything retry automatically?<\/h3><\/dt>\n<dd><p>No. Resending is always a deliberate click. That is intentional: automatic\nretries against a misconfigured server are how a mail problem becomes a mail\nflood.<\/p><\/dd>\n<dt id=\"will%20this%20grow%20into%20a%20pro%20version%20later%3F\"><h3>Will this grow into a pro version later?<\/h3><\/dt>\n<dd><p>No. Staying small is the point of the plugin.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Connection test gives up after ten seconds instead of hanging when host,\nport or encryption are wrong, and says which of them do not match.<\/li>\n<li>The test runs without reloading the screen, so you can see it working.<\/li>\n<li>Resending from the log reloads the table, so the new entry is in it.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<\/ul>","raw_excerpt":"Simple, bloatware-free SMTP email plugin: sends by SMTP, logs the result, resends failures. Minimal and secure on purpose, and it will stay minimal.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/360907","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=360907"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/wonderfulplugins"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=360907"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=360907"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=360907"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=360907"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=360907"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=360907"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}