{"id":345583,"date":"2026-07-31T11:18:17","date_gmt":"2026-07-31T11:18:17","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/lean-smtp\/"},"modified":"2026-07-31T11:17:51","modified_gmt":"2026-07-31T11:17:51","slug":"lean-smtp","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/lean-smtp\/","author":15235348,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"0.3.1","stable_tag":"0.3.1","tested":"7.0.2","requires":"6.0","requires_php":"8.1","requires_plugins":null,"header_name":"Lean SMTP","header_author":"pjaudiomv","header_description":"Routes wp_mail() through an SMTP server or the Amazon SES, Mailgun, or Resend API, with From identity and Reply-To control, wp-config.php overrides, failure alerts, WP-CLI commands, a test-email button, an offline mode for staging, and optional send logging.","assets_banners_color":"4038c1","last_updated":"2026-07-31 11:17:51","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/github.com\/pjaudiomv\/lean-smtp","header_author_uri":"","rating":0,"author_block_rating":0,"active_installs":0,"downloads":18,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","changelog"],"tags":{"0.3.1":{"tag":"0.3.1","author":"pjaudiomv","date":"2026-07-31 11:17:51"}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3629881,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3629881,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256},"icon.svg":{"filename":"icon.svg","revision":3629881,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3629881,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3629881,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250},"banner.svg":{"filename":"banner.svg","revision":3629881,"resolution":false,"location":"assets","locale":false}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["0.3.1"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3629881,"resolution":"1","location":"assets","locale":"","width":1856,"height":3182},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3629881,"resolution":"2","location":"assets","locale":"","width":1856,"height":1246},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3629881,"resolution":"3","location":"assets","locale":"","width":1856,"height":1246},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3629881,"resolution":"4","location":"assets","locale":"","width":1856,"height":908},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3629881,"resolution":"5","location":"assets","locale":"","width":1856,"height":2104}},"screenshots":{"1":"Settings page: pick a mailer \u2014 including Offline, which records mail without sending it \u2014 set the From identity and Reply-To, configure the transport, and choose how much of each message the log keeps.","2":"Amazon SES \u2014 region and IAM access key; the secret key is stored encrypted and never shown.","3":"Mailgun \u2014 sending domain, US\/EU region, and API key.","4":"Resend \u2014 a single API key.","5":"Send a test email, and review the optional send log. When message content is recorded, each row expands to show the headers, attachment names and body that were sent."}},"plugin_section":[],"plugin_tags":[267,450,6929,6696,6695],"plugin_category":[41],"plugin_contributors":[154957],"plugin_business_model":[],"class_list":["post-345583","plugin","type-plugin","status-publish","hentry","plugin_tags-email","plugin_tags-mail","plugin_tags-ses","plugin_tags-smtp","plugin_tags-wp_mail","plugin_category-communication","plugin_contributors-pjaudiomv","plugin_committers-pjaudiomv"],"banners":{"banner":"https:\/\/ps.w.org\/lean-smtp\/assets\/banner-772x250.png?rev=3629881","banner_2x":"https:\/\/ps.w.org\/lean-smtp\/assets\/banner-1544x500.png?rev=3629881","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/lean-smtp\/assets\/icon.svg?rev=3629881","icon":"https:\/\/ps.w.org\/lean-smtp\/assets\/icon.svg?rev=3629881","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/lean-smtp\/assets\/screenshot-1.png?rev=3629881","caption":"Settings page: pick a mailer \u2014 including Offline, which records mail without sending it \u2014 set the From identity and Reply-To, configure the transport, and choose how much of each message the log keeps."},{"src":"https:\/\/ps.w.org\/lean-smtp\/assets\/screenshot-2.png?rev=3629881","caption":"Amazon SES \u2014 region and IAM access key; the secret key is stored encrypted and never shown."},{"src":"https:\/\/ps.w.org\/lean-smtp\/assets\/screenshot-3.png?rev=3629881","caption":"Mailgun \u2014 sending domain, US\/EU region, and API key."},{"src":"https:\/\/ps.w.org\/lean-smtp\/assets\/screenshot-4.png?rev=3629881","caption":"Resend \u2014 a single API key."},{"src":"https:\/\/ps.w.org\/lean-smtp\/assets\/screenshot-5.png?rev=3629881","caption":"Send a test email, and review the optional send log. When message content is recorded, each row expands to show the headers, attachment names and body that were sent."}],"raw_content":"<!--section=description-->\n<p>Lean SMTP makes WordPress send its mail through a real mail service instead of the host's default PHP mail, which improves deliverability. It is deliberately small: a handful of transports, a handful of settings, no upsells.<\/p>\n\n<p>Website: https:\/\/leansmtp.com<\/p>\n\n<p>Every provider below also offers plain SMTP, so the SMTP transport alone covers all of them. The API transports exist for hosts that block outbound mail ports (25\/465\/587), which is common on shared hosting and some managed platforms.<\/p>\n\n<ul>\n<li><strong>SMTP<\/strong> \u2014 any host\/port with TLS, SSL, or no encryption, optional username\/password.<\/li>\n<li><strong>Amazon SES (API)<\/strong> \u2014 the SES v2 API, signed with a hand-rolled AWS Signature V4 signer, so no AWS SDK is bundled.<\/li>\n<li><strong>Mailgun (API)<\/strong> \u2014 US or EU region, sending the message as MIME so attachments and formatting survive untouched.<\/li>\n<li><strong>Resend (API)<\/strong> \u2014 a single API key, nothing else to configure.<\/li>\n<li><strong>Offline<\/strong> \u2014 record every message and send nothing, for staging sites that must never mail real customers. wp_mail() still reports success, so plugins behave exactly as they would in production.<\/li>\n<li><strong>From identity<\/strong> \u2014 set the From name and address, and optionally force them over anything another plugin sets.<\/li>\n<li><strong>Reply-To<\/strong> \u2014 a site-wide default for replies, useful when the From address is a no-reply. A Reply-To the message set itself is always kept.<\/li>\n<li><strong>wp-config.php overrides<\/strong> \u2014 pin any setting in code instead of the database, so credentials can live in environment variables and never diverge between environments.<\/li>\n<li><strong>Failure alerts<\/strong> \u2014 an admin notice when mail stops going out, so a broken mailer isn't discovered via missed password resets. It clears itself once mail works again.<\/li>\n<li><strong>WP-CLI<\/strong> \u2014 <code>wp lean-smtp test<\/code> and <code>wp lean-smtp status<\/code>.<\/li>\n<li><strong>Test email<\/strong> \u2014 a button on the settings page to confirm your configuration works.<\/li>\n<li><strong>Send log<\/strong> \u2014 optional; records the most recent sends (recipient, subject, result) with a viewer and a clear button. The message headers, attachment filenames and body can each be recorded too, behind their own settings and off by default.<\/li>\n<li><strong>Encrypted secrets<\/strong> \u2014 stored passwords and API keys are AES-256 encrypted, keyed to your site salts.<\/li>\n<\/ul>\n\n<p>Deliberately not included: Gmail and Microsoft 365 OAuth. Both need an OAuth consent flow, refresh-token storage, and (for Google) app verification \u2014 more machinery than the rest of this plugin combined. Use an app password or a provider above.<\/p>\n\n<h3>Configuring in wp-config.php<\/h3>\n\n<p>Any setting can be defined as a constant instead of saved in the database. The constant name is the option name in upper case, and it always wins \u2014 the settings page shows the field as read-only and names the constant, so what you see is always what is in force. Removing the constant restores whatever was saved before.<\/p>\n\n<pre><code>define( 'LEAN_SMTP_MAILER', 'ses' );\ndefine( 'LEAN_SMTP_FROM_EMAIL', 'noreply@example.com' );\ndefine( 'LEAN_SMTP_SES_REGION', 'us-east-1' );\ndefine( 'LEAN_SMTP_SES_ACCESS_KEY', 'AKIA\u2026' );\ndefine( 'LEAN_SMTP_SES_SECRET_KEY', getenv( 'SES_SECRET_KEY' ) );\n<\/code><\/pre>\n\n<p>Secrets defined this way are used as-is and are never written to the database. Run <code>wp lean-smtp status<\/code> to see every setting and where it came from.<\/p>\n\n<h3>External services<\/h3>\n\n<p>Lean SMTP sends email through whichever mail service you configure. When \u2014 and only when \u2014 you select an API transport and your site sends mail, the plugin connects to that provider's HTTPS API and transmits the message being sent (recipients, subject, body, headers, and any attachments) along with the credentials you entered, so the provider can authenticate the request and deliver the message. Nothing is sent until you configure and select a transport, and the plugin contacts no other services: there is no telemetry, tracking, or analytics.<\/p>\n\n<p>The provider you choose is the data controller for the mail you route through it. Review its terms and privacy policy:<\/p>\n\n<ul>\n<li>Amazon SES \u2014 sends to <code>email.{region}.amazonaws.com<\/code>. Terms: https:\/\/aws.amazon.com\/service-terms\/ \u00b7 Privacy: https:\/\/aws.amazon.com\/privacy\/<\/li>\n<li>Mailgun \u2014 sends to <code>api.mailgun.net<\/code> or <code>api.eu.mailgun.net<\/code>. Terms: https:\/\/www.mailgun.com\/legal\/terms\/ \u00b7 Privacy: https:\/\/www.mailgun.com\/legal\/privacy-policy\/<\/li>\n<li>Resend \u2014 sends to <code>api.resend.com<\/code>. Terms: https:\/\/resend.com\/legal\/terms-of-service \u00b7 Privacy: https:\/\/resend.com\/legal\/privacy-policy<\/li>\n<\/ul>\n\n<p>The SMTP transport connects only to the host you configure and bundles no third-party service. The Offline mailer connects to nothing at all: messages are written to the local send log and never leave your server.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin and activate it.<\/li>\n<li>Go to Settings \u2192 Lean SMTP.<\/li>\n<li>Choose a mailer and fill in the connection details.<\/li>\n<li>Set your From Email and From Name.<\/li>\n<li>Save, then use \"Send a Test Email\" to confirm it works.<\/li>\n<\/ol>\n\n<p>For Amazon SES: create an IAM user limited to <code>ses:SendRawEmail<\/code>\/<code>ses:SendEmail<\/code>, verify your From address (or domain) in the SES console, and, if your account is still in the SES sandbox, verify the recipient too.<\/p>\n\n<p>For Mailgun: use the sending domain exactly as it appears in your Mailgun dashboard, and pick the region matching the account the key was issued in \u2014 a US key is not valid against the EU stack.<\/p>\n\n<p>For Resend: create an API key with send permission and verify your From domain.<\/p>\n\n<!--section=changelog-->\n<h4>0.3.1<\/h4>\n\n<ul>\n<li>Stored passwords and API keys are no longer passed through sanitize_text_field(), which strips characters that are perfectly legal in a credential (angle brackets, percent-encoded sequences) and could leave a saved secret that no longer authenticates. Only control characters are removed now. If your password or API key contains such characters, re-enter it.<\/li>\n<\/ul>\n\n<h4>0.3.0<\/h4>\n\n<ul>\n<li>Added an Offline mailer: every message is recorded and nothing is sent, for staging sites that must not mail real customers. wp_mail() still reports success, so other plugins behave as they would in production.<\/li>\n<li>The send log can now record the message headers, attachment filenames and body. Each is a separate setting and both are off by default \u2014 a stored body contains password-reset links and anything else your site mails. Recorded content is shown in an expandable row in the log viewer, alongside the full error text for a failed send.<\/li>\n<li>Added a Reply-To setting, applied to both the SMTP and API paths. A Reply-To the message set for itself is always kept.<\/li>\n<li>The log table is now upgraded in place when the plugin is updated. Previously the table was only ever created on activation, which does not run on update.<\/li>\n<\/ul>\n\n<h4>0.2.1<\/h4>\n\n<ul>\n<li>The settings screen's CSS and JavaScript are now enqueued as files on that screen only, instead of being printed inline.<\/li>\n<li>Each setting is now registered with its own named sanitize callback, with the wp-config.php constant guard applied as a separate filter on top.<\/li>\n<\/ul>\n\n<h4>0.2.0<\/h4>\n\n<ul>\n<li>Added a Mailgun transport (US and EU regions), sending the assembled message as MIME.<\/li>\n<li>Added a Resend transport.<\/li>\n<li>Bcc recipients on API sends are now carried as an explicit envelope and the Bcc header is stripped from the delivered message, so hidden recipients are never disclosed to other recipients.<\/li>\n<li>Any setting can now be pinned in wp-config.php as an upper-case constant; a pinned setting renders read-only on the settings page and is left untouched when the form is saved.<\/li>\n<li>Added an admin notice when a send fails, so a silently broken mailer is noticed. It clears itself after the next successful send.<\/li>\n<li>Added WP-CLI commands: <code>wp lean-smtp test [&lt;recipient&gt;]<\/code> and <code>wp lean-smtp status<\/code>.<\/li>\n<li>The API transports now share one message assembly behind a Lean_SMTP_Api_Transport interface, so all of them reproduce core's wp_mail() semantics identically.<\/li>\n<\/ul>\n\n<h4>0.1.1<\/h4>\n\n<ul>\n<li>Fixed Amazon SES sends failing with an HTTP 403 \"signature does not match\" error caused by the secret key being encrypted twice on its first save (WordPress runs a setting's sanitize callback twice when the option is first created). Re-enter your SES secret key (and SMTP password) after updating.<\/li>\n<li>SES requests now sign only the required host and date headers, avoiding signature mismatches when the HTTP transport rewrites the Content-Type header.<\/li>\n<li>Fixed failed SES sends being written to the send log twice; every send is now recorded exactly once.<\/li>\n<\/ul>\n\n<h4>0.1.0<\/h4>\n\n<ul>\n<li>Initial release. SMTP and Amazon SES (API) transports for wp_mail(), From name\/email with optional forcing, a test-email button, optional send logging, and AES-256 at-rest encryption of stored credentials.<\/li>\n<\/ul>","raw_excerpt":"Route wp_mail() through SMTP or the Amazon SES, Mailgun, or Resend API \u2014 with From control, wp-config overrides, and mail-failure alerts.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/345583","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=345583"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/pjaudiomv"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=345583"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=345583"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=345583"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=345583"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=345583"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=345583"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}