=== SendForce Mail SMTP Relay — Free WP SMTP & Email API Plugin for Amazon SES, SendGrid, Mailgun, Brevo, Postmark, Zoho ZeptoMail & Gmail ===
Contributors: shiponkarmakar
Donate link: https://profiles.wordpress.org/shiponkarmakar/
Tags: email, email log, gmail, outlook, smtp
Requires at least: 5.9
Tested up to: 7.0
Stable tag: 1.0.32
Requires PHP: 7.4
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Free WP SMTP & email-API plugin. Send via SES, SendGrid, Mailgun, Brevo, Postmark, ZeptoMail, Gmail & more — with logs, queue & alerts.

== Description ==

**SendForce Mail SMTP is a free, open-source WordPress SMTP plugin** that fixes the "WordPress emails not being delivered" problem in minutes. Send WooCommerce order emails, Contact Form 7 / WPForms / Gravity Forms submissions, password resets, registration confirmations, and any other `wp_mail()` traffic through Amazon SES, SendGrid, Mailgun, Brevo (Sendinblue), Postmark, Zoho ZeptoMail, Gmail API, Microsoft 365, or any standard SMTP server — with full email logging, queue, retry, and failure alerts.

= Why SendForce Mail SMTP =

* **100% Free, no premium upsell.** Every feature you see is included — no "pro version" lock screens, no email-volume cap, no provider unlock paywall. Compare with WP Mail SMTP, Easy WP SMTP, Post SMTP, or FluentSMTP and you'll find SendForce's free tier matches or beats their paid tiers.
* **24+ providers, one plugin.** Built-in presets and HTTP API integrations for the most popular transactional email services — pick what fits your budget, deliverability needs, and region.
* **Built-in debugging.** Live SMTP debug log on test email, raw API request/response capture in the email log, "Copy Debug Info" button for support tickets, and WP-CLI commands. Designed for developers and agencies who need to diagnose email problems fast.
* **Multiple connections with automatic fallback.** Configure a primary connection (e.g. Amazon SES) plus a fallback (e.g. Mailgun). If the primary returns an error, the fallback takes over — no email lost.

= Supported email providers =

**HTTP API sending (recommended — faster and more reliable than SMTP):**

* Amazon SES (AWS Simple Email Service)
* SendGrid (by Twilio)
* Mailgun (by Sinch)
* Brevo (formerly Sendinblue)
* SparkPost
* Postmark
* Zoho ZeptoMail
* Microsoft 365 / Outlook (Microsoft Graph API)
* Gmail / Google Workspace (Gmail API)
* SMTP2GO
* SMTP.com
* Elastic Email
* SocketLabs
* Moosend
* SendLayer
* Mailjet
* MailerSend
* Mandrill (by Mailchimp)
* Resend
* Netcore Email API (formerly Pepipost)

**SMTP sending (works with any provider, including custom servers):**

* Gmail / Google Workspace SMTP (smtp.gmail.com)
* Microsoft 365 / Outlook SMTP (smtp.office365.com)
* Yahoo Mail SMTP
* Zoho Mail SMTP
* Turbo SMTP
* Any other SMTP server (host, port, username, password)

= Features =

* **Multiple connections with automatic fallback** — configure a primary connection (e.g. Amazon SES) plus a fallback (e.g. Mailgun, SMTP, or PHP mail). If the primary returns an error, the fallback is attempted automatically. Both attempts are logged so you have a full audit trail; recovered emails carry a "Recovered via fallback" badge in the log detail view.
* **Smart Routing Rules** — send different emails through different connections based on rules you define. Match by recipient domain, recipient pattern (glob), sender email or domain, source plugin (auto-detected for WooCommerce, Contact Form 7, WPForms, Gravity Forms, Ninja Forms, Fluent Forms, Forminator, Easy Digital Downloads, MemberPress, LearnDash, MailPoet, BuddyPress, bbPress and more), subject contains, time of day, or weekday. Rules are evaluated top-down (first match wins) and can target a single connection, a round-robin pool, or WordPress phpmail(). Includes inline rule editor, master enable/disable toggle, "Test Routing" tool, and a "via rule:" badge on the Email Log so you can see exactly which rule fired for any send.
* **One-click provider presets** — pre-filled host, port, encryption, and API endpoint for every supported provider. Just paste your API key or password.
* **Email Log** — every outgoing email logged with status, recipient, subject, headers, error message, and timestamp. Filter by status, search by keyword, filter by date range, export to CSV or JSON.
* **Email Queue with retry** — queue mode prevents rate-limit errors and timeouts on bulk sends. Failed emails auto-retry on exponential backoff (5 min → 15 min → 45 min).
* **Email Test page** — send a test email with live SMTP debug log output. Diagnose connection problems instantly.
* **Failure alerts** — push delivery failures to Telegram, Slack, Discord, Microsoft Teams, Google Chat, Pushover, or any custom webhook.
* **Sender Identity override** — force every email to use a custom From name and From address site-wide.
* **Conflict detection** — warns you if another SMTP plugin (WP Mail SMTP, FluentSMTP, Easy WP SMTP, Post SMTP, etc.) is active so you can deactivate it before things break.
* **Encrypted credential storage** — SMTP passwords and API keys are encrypted at rest using AES-256-CBC with WordPress security salts.
* **WP-CLI commands** — `wp sendforce test`, `wp sendforce queue process`, `wp sendforce log list`, `wp sendforce sysinfo`.
* **Developer hooks** — `sendforce_before_send`, `sendforce_after_send`, `sendforce_log_entry`, `sendforce_api_request`, `sendforce_api_response` for extending the plugin without forking.
* **`WP_DEBUG_LOG` integration** — optional mirroring of SMTP and API debug output to `debug.log`.
* **Automatic log cleanup** — configurable retention period (default 30 days).
* **Privacy-friendly** — optional disable of email-body logging for GDPR / privacy compliance.
* **Multisite compatible.**

= Works with all major WordPress plugins =

SendForce Mail SMTP hooks into WordPress's core `wp_mail()` function, so it works with **every** plugin that sends email — including WooCommerce, Easy Digital Downloads, Contact Form 7, WPForms, Gravity Forms, Ninja Forms, Fluent Forms, Forminator, MemberPress, LearnDash, BuddyPress, bbPress, MailPoet (transactional), and any custom plugin or theme that uses `wp_mail()`.

== Installation ==

1. Upload the `sendforce-mail-relay` folder to the `/wp-content/plugins/` directory, or install directly through the WordPress plugin installer.
2. Activate the plugin through the **Plugins** menu in WordPress.
3. Go to **SendForce Mail Relay > Settings** to configure your SMTP server or API credentials.
4. Select your email provider from the provider grid.
5. Enter your credentials and click **Save Settings**.
6. Go to **SendForce Mail Relay > Email Test** and send a test email to verify your configuration.

== Frequently Asked Questions ==

= Do I need an SMTP server or API account? =

Yes. You need access to an SMTP server or a transactional email provider account. Most providers (Gmail, Outlook, etc.) offer SMTP access. Transactional services like SendGrid, Mailgun, or Amazon SES offer both SMTP and HTTP API access.

= Is my SMTP password or API key stored securely? =

Yes. All credentials are encrypted using AES-256-CBC encryption with a key derived from your WordPress security salts before being stored in the database.

= What does the email queue do? =

When enabled, emails are stored in a database queue instead of being sent immediately. A WP-Cron job processes the queue every 5 minutes, sending emails in batches. Failed emails are retried with exponential backoff (5 min → 15 min → 45 min).

= Will SendForce Mail Relay send ALL WordPress emails including WooCommerce? =

Yes. SendForce Mail Relay hooks into WordPress's `phpmailer_init` action (SMTP mode) or `pre_wp_mail` filter (API mode). Since every plugin — including WooCommerce, contact form plugins, and membership plugins — sends email via WordPress's `wp_mail()` function, SendForce Mail Relay will handle 100% of outgoing emails.

= Will this plugin conflict with other SMTP plugins? =

You should only use one SMTP plugin at a time. Please deactivate any other SMTP or email plugins (FluentSMTP, WP Mail SMTP, etc.) before activating SendForce Mail Relay.

= What data is logged? =

By default, SendForce Mail Relay logs: recipient email, subject, headers, status (sent/failed), error message if any, and timestamp. Email body logging is optional and can be disabled in Settings > Queue & Logging for privacy compliance.

= What happens to my data when I uninstall the plugin? =

All plugin data (database tables, settings, and scheduled events) is completely removed when you delete the plugin through the WordPress admin.

= Does this plugin track me or phone home? =

No. SendForce Mail Relay does not collect any data, make any analytics calls, or communicate with any external server except when sending emails through your configured provider.

== External Services ==

SendForce Mail Relay is an email-delivery plugin. It does NOT connect to any external service automatically. A connection is made ONLY after you explicitly configure a provider and either (a) WordPress sends an outgoing email, or (b) you click "Send Test Email", or (c) you enable a notification channel and an email-failure alert is dispatched.

For each configured email provider, the data sent on every send is the same set of fields WordPress would otherwise hand to the local mail() function: the recipient address(es), CC, BCC, Reply-To, From name/address, subject, message body, headers, and attachments. No additional telemetry or analytics is transmitted by this plugin.

For each configured notification channel (Telegram, Slack, Discord, Microsoft Teams, Google Chat, Pushover, custom Webhook), the data sent is a short status message you compose in the plugin (default: failed-delivery summary or daily summary).

= Email-delivery providers (configurable in Settings → Connections) =

**SendGrid (by Twilio)**
* Service: https://sendgrid.com
* When data is sent: every WordPress email when SendGrid is the active connection, plus on test-email click.
* Endpoint: https://api.sendgrid.com/v3/mail/send
* Privacy Policy: https://www.twilio.com/en-us/legal/privacy
* Terms of Service: https://www.twilio.com/en-us/legal/tos

**Mailgun (by Sinch)**
* Service: https://www.mailgun.com
* When data is sent: same as above, but to Mailgun.
* Endpoint: https://api.mailgun.net/v3/{domain}/messages (US) or https://api.eu.mailgun.net/v3/{domain}/messages (EU).
* Privacy Policy: https://www.mailgun.com/legal/privacy-policy/
* Terms of Service: https://www.mailgun.com/legal/terms/

**Amazon SES (AWS Simple Email Service)**
* Service: https://aws.amazon.com/ses/
* When data is sent: same.
* Endpoint: https://email.{region}.amazonaws.com/v2/email/outbound-emails (region you select).
* Privacy Policy: https://aws.amazon.com/privacy/
* Terms of Service: https://aws.amazon.com/service-terms/

**Brevo (formerly Sendinblue)**
* Service: https://www.brevo.com
* Endpoint: https://api.brevo.com/v3/smtp/email
* Privacy Policy: https://www.brevo.com/legal/privacypolicy/
* Terms of Service: https://www.brevo.com/legal/termsofuse/

**SparkPost**
* Service: https://www.sparkpost.com
* Endpoint: https://api.sparkpost.com/api/v1/transmissions
* Privacy Policy: https://www.sparkpost.com/policies/privacy/
* Terms of Service: https://www.sparkpost.com/policies/tou/

**Postmark**
* Service: https://postmarkapp.com
* Endpoint: https://api.postmarkapp.com/email
* Privacy Policy: https://postmarkapp.com/privacy-policy
* Terms of Service: https://postmarkapp.com/terms-of-service

**Elastic Email**
* Service: https://elasticemail.com
* Endpoint: https://api.elasticemail.com/v4/emails
* Privacy Policy: https://elasticemail.com/legal/privacy-policy
* Terms of Service: https://elasticemail.com/legal/terms-of-use

**SMTP2GO**
* Service: https://www.smtp2go.com
* Endpoint: https://api.smtp2go.com/v3/email/send
* Privacy Policy: https://www.smtp2go.com/privacy/
* Terms of Service: https://www.smtp2go.com/terms/

**Netcore Email API (formerly Pepipost)**
* Service: https://netcorecloud.com
* Endpoint: https://emailapi.netcorecloud.net/v5/mail/send
* Privacy Policy: https://netcorecloud.com/privacy-policy
* Terms of Service: https://netcorecloud.com (request the latest terms via the contact form on the homepage; Netcore does not publish a stable terms-of-use URL).

**SMTP.com**
* Service: https://www.smtp.com
* Endpoint: https://api.smtp.com/v4/messages
* Privacy Policy: https://www.smtp.com/policies/privacy-policy/
* Terms of Service: https://www.smtp.com/legal/terms/

**SocketLabs**
* Service: https://www.socketlabs.com
* Endpoint: https://inject.socketlabs.com/api/v1/email
* Privacy Policy: https://www.socketlabs.com/legal/privacy-policy/
* Terms of Service: https://www.socketlabs.com/legal/

**Moosend (by Sitecore)**
* Service: https://moosend.com
* Endpoint: https://api.moosend.com/v3/
* Privacy Policy: https://moosend.com/privacy-policy/
* Terms of Service: https://moosend.com/terms/

**SendLayer**
* Service: https://sendlayer.com
* Endpoint: https://console.sendlayer.com/api/v1/email
* Privacy Policy: https://www.sendlayer.com/privacy-policy/
* Terms of Service: https://www.sendlayer.com/terms-of-service/

**Mailjet (by Sinch)**
* Service: https://www.mailjet.com
* Endpoint: https://api.mailjet.com/v3.1/send
* Privacy Policy: https://www.sinch.com/legal/privacy-notice/
* Terms of Service: https://www.sinch.com/legal/terms-of-service/

**MailerSend**
* Service: https://www.mailersend.com
* Endpoint: https://api.mailersend.com/v1/email
* Privacy Policy: https://www.mailersend.com/legal/privacy-policy
* Terms of Service: https://www.mailersend.com/legal/terms-of-use

**Mandrill (by Mailchimp)**
* Service: https://mailchimp.com/developer/transactional/
* Endpoint: https://mandrillapp.com/api/1.0/messages/send.json
* Privacy Policy: https://mailchimp.com/legal/privacy/
* Terms of Service: https://mailchimp.com/legal/terms/

**Resend**
* Service: https://resend.com
* Endpoint: https://api.resend.com/emails
* Privacy Policy: https://resend.com/legal/privacy-policy
* Terms of Service: https://resend.com/legal/terms-of-service

**Zoho ZeptoMail**
* Service: https://www.zoho.com/zeptomail/
* Endpoint: https://api.zeptomail.com/v1.1/email
* Privacy Policy: https://www.zoho.com/privacy.html
* Terms of Service: https://www.zoho.com/zeptomail/terms.html

**Microsoft 365 / Outlook (Microsoft Graph API and SMTP)**
* Service: https://www.microsoft.com/microsoft-365
* Endpoint (API): https://graph.microsoft.com/v1.0/users/{user}/sendMail (OAuth token from https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token)
* Endpoint (SMTP): smtp.office365.com:587
* Privacy Policy: https://privacy.microsoft.com/en-US/privacystatement
* Terms of Service: https://www.microsoft.com/en-us/servicesagreement/

**Gmail / Google Workspace (Gmail API and SMTP)**
* Service: https://workspace.google.com
* Endpoint (API): https://gmail.googleapis.com/gmail/v1/users/me/messages/send (OAuth token from https://oauth2.googleapis.com/token)
* Endpoint (SMTP): smtp.gmail.com:587
* Privacy Policy: https://policies.google.com/privacy
* Terms of Service: https://policies.google.com/terms

= Notification channels (configurable in Settings → Alerts) =

These services are contacted ONLY when a notification channel is enabled AND a delivery failure (or daily-summary) event triggers an alert. The data sent is the short status text shown in the plugin's alert preview.

**Telegram (Bot API)**
* Service: https://telegram.org
* When data is sent: when a Telegram channel is enabled, a failed-delivery alert or daily-summary alert is generated.
* Endpoint: https://api.telegram.org/bot{token}/sendMessage
* Privacy Policy: https://telegram.org/privacy
* Terms of Service: https://telegram.org/tos

**Pushover**
* Service: https://pushover.net
* Endpoint: https://api.pushover.net/1/messages.json
* Privacy Policy: https://pushover.net/privacy
* Terms of Service: https://pushover.net/terms

**Slack (Incoming Webhooks)**
* Service: https://slack.com
* Endpoint: the webhook URL you paste (https://hooks.slack.com/services/...).
* Privacy Policy: https://slack.com/trust/privacy/privacy-policy
* Terms of Service: https://slack.com/legal

**Discord (Webhooks)**
* Service: https://discord.com
* Endpoint: the webhook URL you paste (https://discord.com/api/webhooks/...).
* Privacy Policy: https://discord.com/privacy
* Terms of Service: https://discord.com/terms

**Microsoft Teams (Incoming Webhooks)**
* Service: https://www.microsoft.com/microsoft-teams/
* Endpoint: the Teams webhook URL you paste.
* Privacy Policy: https://privacy.microsoft.com/en-US/privacystatement
* Terms of Service: https://www.microsoft.com/en-us/servicesagreement/

**Google Chat (Incoming Webhooks)**
* Service: https://chat.google.com
* Endpoint: the Google Chat webhook URL you paste.
* Privacy Policy: https://policies.google.com/privacy
* Terms of Service: https://workspace.google.com/terms/premier_terms.html

**Custom Webhook**
* When data is sent: when a custom Webhook channel is enabled and an alert is generated, a JSON payload is POSTed to the URL you paste.
* Endpoint: the URL you paste.
* Privacy Policy / Terms: governed by the operator of the URL you provide.

= Bundled third-party libraries (no network call) =

**Chart.js (https://www.chartjs.org)** — bundled locally at assets/js/chart.umd.min.js (v4.5.0). Used to render the email-stats chart on the dashboard. Loaded entirely from your own server; no CDN call is made.

== Privacy Policy ==

SendForce Mail Relay stores the following data in your WordPress database:

* **Email logs** (if logging is enabled): recipient email address, subject, headers, email body (optional), sent status, error messages, and timestamps.
* **Email queue** (if queue is enabled): same data as above, plus retry attempt count and next retry time.
* **Plugin settings**: your SMTP host, port, username, and encrypted password or API key.

Email body logging can be disabled in **Settings > Queue & Logging**. Log entries are automatically deleted after the configured retention period (default: 30 days). All data is deleted when the plugin is uninstalled.

We recommend adding a note to your site's privacy policy if you log email content, informing users that outgoing email metadata may be stored.

== Screenshots ==

1. Modern dashboard with connection status, email statistics, and 7-day send chart.
2. Settings page with visual provider grid and SMTP/API tab switcher.
3. Email Log with status filters, keyword search, and date range filtering.
4. Email Test page with live SMTP debug log output.
5. Email Queue management with retry statistics.

== Changelog ==

For the **complete** release history with full detail on every change, see [CHANGELOG.md](https://plugins.svn.wordpress.org/sendforce-mail-relay/trunk/CHANGELOG.md) (also bundled with the plugin) or open the **What's New** tab inside SendForce in your WordPress admin. The section below is condensed to fit within WordPress.org's 5,000-word changelog limit.

= 1.0.32 =
* Compatibility: Verified compatible with WordPress 7.0 — bumped the "Tested up to" header so the wp.org compatibility warning clears for sites already running the latest WordPress.
* Maintenance: Refreshed the wp.org plugin directory tags (`email`, `email log`, `gmail`, `outlook`, `smtp`) to better match how users actually search. `gmail` and `outlook` in particular are high-intent searches that match our existing Gmail and Microsoft 365 OAuth flows but weren't previously tagged.

= 1.0.31 =
* Fix: **Email Log "Connection" filter was dropped when paginating or exporting** (regression introduced with the new dropdown in 1.0.30). Picking a connection, then clicking page 2 or "Export CSV/JSON", silently reset the filter and returned all providers. Both the pagination base URL and the export URL now preserve the active provider value, so paging through SendGrid-only results stays SendGrid-only and "Export CSV" of a filtered view exports just the filtered rows.
* Polish: Accessibility — icon-only **View** button on the Email Log row and the **Retry** / **Delete** buttons on the Queue row now expose an `aria-label` so screen readers announce them correctly (was relying on `title` alone, which most assistive tech ignores).
* Polish: Bulk action counter on the Email Log ("X item(s)") now uses proper plural forms via `_n()`, so non-English locales can translate the singular and plural cases separately instead of inheriting the awkward English "(s)" suffix.
* Polish: Settings → Developer Debug toggle label changed from "Mirror SMTP & API debug output" to "Mirror SMTP and API debug output" (a literal `&` in a translation string is a portability gotcha for some PO editors).
* Polish: Alerts tab — added `viewBox` (camelCase) to the SVG `wp_kses` whitelist alongside the existing lowercase `viewbox`, so channel-logo SVGs render correctly regardless of which casing the source file uses.
* Internal: Renamed `$current_user` to `$sendforce_current_user` in the Email Test template for prefix consistency with the rest of the file (avoids accidentally shadowing WP's globally-scoped `$current_user` in deeply included contexts).

= 1.0.30 =
* New: **Filter Email Log by connection.** A new "Connection" dropdown in the Email Log filter bar lets you narrow the table down to emails sent through a specific provider (Amazon SES, SendGrid, Microsoft 365, etc.). Useful when you run several connections side-by-side and want to audit just one — e.g. "show me everything WooCommerce sent via SendGrid this week". Options are populated from connections that actually have log entries (no empty dropdown choices). Existing log rows from before 1.0.30 don't carry a provider value and stay visible under the "All connections" default.
* New: **"Copy diagnostic snapshot" button** on the Email Log detail modal. Bundles the log ID, timestamp, status, error, headers, attachments, and the (already-redacted) raw API request/response into one clipboard-friendly text block — pre-formatted for pasting straight into a support ticket. Plugin / WordPress / PHP versions are included automatically. No more copy-paste-merge of six different fields when reporting an issue.
* Internal: Added `provider` column to `wp_sendforce_logs` (varchar(50), indexed). Populated automatically going forward from the captured debug payload (when available) or the active connection's configured provider. Existing rows are not back-filled; only new log entries get the column populated. dbDelta handles the schema migration on plugin upgrade.

= 1.0.29 =
* Fix: **Stray gray "pill" elements rendering on the What's New tab** (introduced in 1.0.28). The changelog accordion's markdown-to-HTML converter wrapped backtick-delimited text in `<code>` tags but didn't escape the inner content first — so when a bullet contained literal `<tag>` text inside backticks (very common in technical changelogs), the browser interpreted the embedded text as a real HTML tag and produced floating empty `<code>` elements that rendered as gray pills against the page background. Fix: `esc_html()` the raw line before applying the markdown transformations. The two regex rules (`**bold**` → `<strong>` and backtick → `<code>`) now run on already-escaped text, guaranteeing balanced tags and no HTML injection from bullet content. Affects 1.0.28 only.
* Fix: **WordPress 6.7+ "Translation loading triggered too early" notice** caused by the custom cron schedule's display label being translated inside the `cron_schedules` filter. The filter fires whenever WP looks up scheduled events (which can happen before `init`, during plugins_loaded or even setup_theme), so calling `__( …, 'sendforce-mail-relay' )` there ran the translation function before the textdomain was loaded. Both filter callbacks (in the activator and the mailer) now use a literal English string for the cron schedule's `display` label — that label is only shown in dev tools like WP Crontrol or `wp-cli cron list`, never user-facing, so leaving it untranslated is harmless. Resolves the deprecation notice on sites running WP_DEBUG with WP 6.7 or newer.

= 1.0.28 =
* New: **Test send now shows the full provider response inline** on the Email Test page. When a test fails the headline shows the short reason ("Failed to send via Microsoft 365 API") and a new "Provider response" panel below it shows the raw HTTP response body — pretty-printed when it's JSON, with a one-click Copy button for support tickets. Previously the full Graph/SES/Mailgun response was only visible by clicking into the Email Log; users debugging a misconfiguration now see everything they need without leaving the test page.
* New: **HTTPS warning on webhook URL fields** (Slack, Discord, Microsoft Teams, Google Chat, generic Webhook). As soon as you paste/type a URL starting with `http://` an inline red warning appears explaining that the alert message (site name, failed recipient, error details) would be sent unencrypted. Catches typos and homemade webhook receivers before save.
* New: **"Welcome to v{X.Y.Z}" admin notice** after the plugin updates, with a one-click button to the in-admin "What's New" tab. Per-user dismissible, only shows once per version, never on fresh installs or on SendForce's own settings pages (where the tab is already visible). Helps users discover what changed without having to read the wp.org changelog page.
* New: **Failure-alert rate limiting**, default 5-minute window per channel. A burst of failed sends (e.g. WooCommerce sending 100 order emails through an expired API key) no longer floods Slack/Telegram/Discord/Teams with 100 identical pings — within the window the first one fires, the rest are counted and rolled up into a "(+N additional failures were suppressed)" note on the next alert after the window expires. Filter `sendforce_alerts_throttle_seconds` to change the window length, set it to 0 to disable throttling entirely.
* Docs: Added **CHANGELOG.md** with the complete, full-detail release history for every version (no length limit). The condensed Changelog in this readme.txt covers the WordPress.org 5,000-word cap; CHANGELOG.md carries the full story for anyone who wants it.
* In-admin: The **What's New** tab now reads from CHANGELOG.md when present (falls back to readme.txt). Browse every release's full bullet list inline in WordPress without going to wp.org or GitHub.
* Older entries (1.0.0 – 1.0.20) in this readme.txt are now one-line summaries; their full detail lives in CHANGELOG.md and the in-admin Changelog accordion. Recent releases (1.0.21+) remain fully detailed in both places.

= 1.0.27 =
* Security (defense-in-depth): **Bulk-delete logs and queue retry/delete actions now require `manage_options` capability** in addition to the existing nonce check. The forms that issued these requests already live on admin-only pages, so a non-admin couldn't normally obtain a valid nonce — but explicit capability checks match WordPress.org Plugin Check expectations and protect against any future flow that might mint a nonce in a less-restricted context.
* Privacy: **Email Log now stores only the filename basenames of attachments** instead of full filesystem paths. Previously rows like `/var/www/example.com/wp-content/uploads/woocommerce_uploads/2026/invoice-12345.pdf` were stored verbatim — leaking the server directory layout, shared-hosting username paths, and customer order IDs from WooCommerce invoice filenames. From 1.0.27 the same row stores only `invoice-12345.pdf`. Existing rows are not rewritten; only new log entries get basename-only.

= 1.0.26 =

**Sending — attachments and multipart_text across all 18 API providers.**

* New: **Attachments now work in API mode for every supported provider.** 1.0.25 added it for Amazon SES and Gmail; 1.0.26 closes the gap for the remaining 16: SendGrid, Brevo, Mailgun, Postmark, Mailjet, MailerSend, Mandrill, Pepipost / Netcore, SocketLabs, SMTP2GO, SMTP.com, SendLayer, SparkPost, Elastic Email, Resend, and Moosend. Plugin-attached files (WooCommerce PDF invoices, Contact Form 7 / WPForms / Gravity Forms uploads, LearnDash / LifterLMS certificates, anything passed to `wp_mail()`'s 5th argument) are now base64-encoded into each provider's native JSON schema and delivered through the API.
* New: **"Multi-Part Plain Text" setting now applies to API-mode sends across the board.** When the message is HTML and the toggle is on, the auto-derived `text/plain` alternative is included via each provider's native multipart fields. Improves deliverability — Gmail and other inbox providers favour multipart-alternative messages, and plain-text-only clients get a readable fallback. Previously this setting was silently ignored in API mode for the 16 providers covered here.
* Known limitation: Moosend's transactional API has a single `Content` field with no `IsContentHtml` companion for both parts, so it can't represent multipart_text — its attachments work, just not the dual-body part.
* Special-case: Mailgun's attachment endpoint requires `multipart/form-data` (not JSON like the other 17), so a new `build_multipart_form_data()` helper in the base class assembles the request body correctly while still capturing the response into the debug log.
* Internal: Two new base-class helpers — `prepare_attachments()` (base64 + MIME-type detection + safe file reads) and `get_plain_text_alt()` (HTML→plain conversion when multipart_text is on) — give each provider ~5 lines of mapping code instead of duplicating the same boilerplate 18 times.

**Email Queue — actual error messages + on-demand processing.**

* Fix: **Queued emails that fail now record the actual provider error** in the queue row's `error` column. Previously every failure showed a generic "Failed to send email." message, regardless of whether the cause was an expired OAuth token, an unverified sender domain, a wrong API key, or a network glitch. The queue processor now hooks `wp_mail_failed` during each send attempt and stores the real WP_Error message (e.g. `AADSTS70008: refresh token expired`, `MessageRejected: Email address is not verified`, `Domain not found`). Users on the Queue tab can finally see WHY a send failed without digging into the Email Log.
* New: **"Process Queue Now" button** on the Queue tab. Triggers the same processor that WP-Cron runs every 5 minutes, but on demand — useful right after fixing a connection or when testing the queue end-to-end. Disabled when there's nothing queued; only visible when the queue is actually enabled in Settings.
* New: **Queue-disabled info notice** on the Queue tab. Previously visiting the tab with the feature off showed an empty table with no explanation; now there's a clear "Queue is disabled — emails are sent immediately. Enable in Settings → Email Queue." banner with a deep link.
* New: **"Next automatic run" timestamp** shown above the queue list when the queue is enabled, formatted using the site's date/time format. Removes the mystery of "when will my queued emails actually go out".
* Fix: **Test sends bypass the queue.** With queue mode enabled, clicking "Send Test" used to queue the message and report immediate success — but the actual delivery wouldn't happen until the next cron run, which made the test page useless for verifying provider configuration. A new one-shot `SendForce_Queue::$bypass_once` flag tells the queue interceptor to skip the next wp_mail call, so test sends always go out synchronously regardless of queue mode.

**Admin — release history and roadmap in one place.**

* New: **"What's New" tab** combines the upcoming-features roadmap (formerly "What's Next") and the full release history into one navigation entry. Roadmap cards render at the top as before; the changelog sits below as a collapsible accordion.
* New: **Collapsible changelog accordion**, FAQ-style. Each release row shows version + change count; click to expand the bullets. The current installed version auto-expands; everything else stays collapsed by default — ~60% less vertical space than rendering everything flat. Uses native HTML `<details>`/`<summary>` so it's keyboard-accessible and works without JavaScript.
* Renamed: "What's Next" → "What's New". The old `?tab=upcoming` and `?tab=changelog` URLs both still resolve as back-compat aliases so any bookmarks or in-plugin links keep working.

= 1.0.25 =
* New: Email attachments now work with Amazon SES and Gmail API modes (multipart/mixed). Multi-Part Plain Text setting also applies in API mode.
* Fix: Non-ASCII subjects and From-names (Café, résumé, 주문) are now RFC 2047 base64-encoded.
* Refactor: SES and Gmail mailers share a single `build_raw_mime()` helper. Full release detail in CHANGELOG.md.

= 1.0.24 =
* Fix (critical): Microsoft 365 / Gmail OAuth `AADSTS50011` redirect URI mismatch. Root cause was `add_query_arg()` not URL-encoding values, leaving `&` characters bare inside redirect_uri. Switched to `http_build_query()` with `PHP_QUERY_RFC3986`.
* New: OAuth consent now opens in a popup window with graceful redirect fallback; callback splash signals the parent via localStorage + postMessage + closed-polling (survives COOP severance).
* Fix: Microsoft 365, Amazon SES, Gmail, and Mailgun send failures now surface the actual provider error in the UI and Email Log (all four mailers now route through `make_request()`).
* New: Tolerate users pasting `Bearer TOKEN` / `Zoho-enczapikey TOKEN` prefixes — auto-stripped before constructing the auth header. All API keys are also auto-trimmed.
* New: Per-provider API-key hint under the field. Client-side + server-side rejection of GUID-shaped Azure Secret IDs pasted into the Client Secret field. Rewrote Gmail and Microsoft 365 OAuth setup instructions. Full release detail in CHANGELOG.md.

= 1.0.23 =
* Fix: OAuth redirect URI is now constructed defensively against third-party `admin_url` filters (Wordfence, LiteSpeed Cache).
* i18n: Email Log "Next run" timestamp now uses the site's configured date/time format.
* Hardening: Expanded `wp_kses` SVG whitelist used for channel logos on the Alerts tab.

= 1.0.21 =
* New: "Clean Now" button on the Email Log + auto-clean status row showing retention, next run, and a deep-link to settings.
* New: "via rule: <label>" badge on Email Log entries when an email was redirected by a Smart Routing rule.
* New: "Connection missing" warning on routing rule cards when a rule points at a deleted connection.
* New: Real channel logos on the Alerts tab (Slack, Discord, Teams, Telegram, Google Chat, Pushover, Webhook).
* Improvement: Test Routing tool now uses the exact same matcher as the live mailer (no drift between predicted and actual routing).
* Fix: Alert channels were occasionally wiped when saving the Summary Email form. Full release detail in CHANGELOG.md.

= 1.0.20 =
* Admin top navigation layout fixes at narrow widths (tablet/mobile, mid-size laptops). Tab labels collapse to icon-only below 1340px. Logo gets proper left padding on mobile.

= 1.0.19 =
* New: **Smart Routing Rules** — send different emails through different connections by recipient domain/pattern, source plugin (auto-detected for WooCommerce, CF7, WPForms, Gravity Forms, Ninja Forms, Fluent Forms, Forminator, EDD, MemberPress, LearnDash, MailPoet, BuddyPress, bbPress), subject contains, time of day, weekday. Top-down evaluation, first match wins. Includes Routing tab, inline rule editor, master enable toggle, `from_email` / `from_domain` conditions, "via rule" badge in Email Log, starter presets, "What's Next" roadmap tab, styled confirm dialogs.

= 1.0.18 =
* Fixed misleading "Connected" status on Gmail / Microsoft 365 OAuth panel — now checks API mode + Client ID + Client Secret + refresh token all present (not just any password field value). Added amber "partial credentials" state. Hint to switch to API mode when in SMTP. Polished status indicator dot.

= 1.0.17 =
* Initialize `oauth_email` field on newly created connections so the schema is consistent from save time.

= 1.0.16 =
* New: **One-click "Connect with Google" and "Connect with Microsoft" OAuth buttons** replace manual refresh-token generation via OAuth Playground / Azure CLI. Refresh token captured automatically, stored encrypted, panel shows "Connected as user@example.com" with Disconnect button. Bring-your-own-credentials — no third-party OAuth proxy. Microsoft 365 supports both delegated and app-only flows. Setup help panel with copy-able redirect URI.

= 1.0.15 =
* Audited all 20 provider integrations against current docs. 18 verified spec-compliant. Fixed Moosend HTML content-type detection (explicit `IsContentHtml` flag in both HTML and plain-text paths).

= 1.0.14 =
* Fixed Email Queue orphan-row bug: rows stuck in "processing" state after cron timeout / PHP crash now recover via a 10-minute lease (`next_retry_at`) on the next cron run.

= 1.0.13 =
* Security: hardened PHP-mail fallback against header injection (strips CR/LF/null from To, Subject, headers). Validated attachment paths against safe roots (prevents path traversal). Sanitized fallback-connection label. Server-side `wp_strip_all_tags` on provider errors returned to the browser.

= 1.0.12 =
* Renamed "Default Connection" → "Primary Connection" throughout the admin UI (internal storage key unchanged). Provider status dot reflects configuration status (not brand colour). Fixed fallback flow so `wp_mail()` returns true on fallback success; clearer recovery message. Suppressed spurious SMTP-warning when active path was API or PHP-Mail.

= 1.0.11 =
* Plugin Name header is now clean brand name "SendForce Mail Relay" (was long SEO title); Description is a single-line summary. WordPress.org listing keeps the longer SEO title for directory search.

= 1.0.10 =
* New UI controls for **Developer Debug** toggle and **Max Retry Attempts** (1–10). Hardened From-email validation (admin notice on invalid). Replaced native `<select>` dropdowns with branded styled component (full keyboard support — Arrow/Enter/Escape). Default/Fallback selectors auto-refresh after connection save. Form-control polish (chevron, focus ring, hover, disabled states).

= 1.0.9 =
* WordPress.org listing title tuned to "SendForce Mail SMTP Relay — Free WP SMTP & Email API Plugin for Amazon SES, SendGrid, Mailgun, Brevo, Postmark, Zoho ZeptoMail & Gmail" for better directory search. Internal product name unchanged.

= 1.0.8 =
* New: **Automatic fallback connection** — when primary send fails, SendForce retries via configured fallback. Works across any API → API, API → SMTP, SMTP → API, SMTP → SMTP, or any → PHP-mail combination. Both attempts logged; recovered emails get a "Recovered via fallback" badge. Improved readme Description for WordPress.org discoverability.

= 1.0.7 =
* Public display name updated for WordPress.org search index discoverability. Refreshed Tags to highest-volume search terms. Polished connection-row Edit/Delete buttons with dashicons. Added Dashboard / Settings / Email Log / Queue / Test / Alerts sub-menu entries.

= 1.0.6 =
* Shortened WordPress admin sidebar label to "SF Mail Relay" so it fits one line. Added sub-menu entries reachable from sidebar fly-out.

= 1.0.5 =
* Removed accidental `.DS_Store` file from `assets/images/providers/`. Added `phpcs:ignore` annotations with rationale to interpolated table-name `$wpdb` queries. Restructured WP-CLI log-delete query for proper phpcs handling.

= 1.0.4 =
* Updated bundled Chart.js to 4.5.0. Expanded External Services section in readme. Removed inline `<style>`/`<script>` blocks from PHP output (proper enqueue). Surface actual provider HTTP status / response body in failure messages. Added "Raw API request / response" panel to Email Log detail modal. Masked-dots placeholder for saved password/API-key fields. Hardened secret redaction (covers `client_secret`, response bodies, malformed-JSON fallback). Defused CSV formula injection on log export. Gated on-load DB schema upgrade to admin/WP-CLI. Added confirmation prompts to destructive WP-CLI commands.

= 1.0.3 =
* Added WP-CLI commands (`wp sendforce test`, `queue`, `log`, `sysinfo`). Added developer hooks (`sendforce_before_send`, `sendforce_after_send`, `sendforce_log_entry`, `sendforce_api_request`, `sendforce_api_response`). Added Developer Debug setting to mirror SMTP/API debug to `debug.log`. Added raw API request/response capture in new `debug_data` log column (with Authorization redaction). Email Log export as CSV/JSON. "Copy Debug Info" button on Email Test screen. Replaced stale "SMTP-Manager" User-Agent on Resend with "SendForce-Mail-Relay".

= 1.0.1 =
* Added Microsoft 365 Graph API and Gmail API support. Added 5 new providers (SendLayer, Mailjet, MailerSend, Mandrill, Resend). Added Zoho ZeptoMail API. Added 3 new notification channels (Microsoft Teams, Google Chat, Custom Webhook). SVG provider logos. Collapsible provider grid. Fixed multiple API mailer bugs (SendLayer field names, Pepipost endpoint, SparkPost CC, SES BCC, MailerSend Reply-To). Added CC/BCC/Reply-To to Elastic Email, SMTP2GO, SMTP.com, SocketLabs, Moosend, Pepipost. Auto-set first connection as Default. Bundled Chart.js locally. Fixed all Plugin Check warnings. Renamed main file to `sendforce-mail-relay.php`.

= 1.0.0 =
* Initial release. SMTP with 18 provider presets. HTTP API for 12 providers (SendGrid, Mailgun, SES, Brevo, SparkPost, Postmark, Elastic Email, SMTP2GO, Pepipost, SMTP.com, SocketLabs, Moosend). From name/email override. Email logging with search/filter. Email queue with exponential backoff retry. Email Test page with live SMTP debug. AES-256-CBC encrypted credential storage. Auto log cleanup. Modern admin dashboard with 7-day send chart.

== Upgrade Notice ==

= 1.0.30 =
Two Email Log enhancements: filter by connection (audit one provider at a time) and a one-click "Copy diagnostic snapshot" button on log detail (bundles all the info needed for a support ticket into one clipboard blob). Schema migration adds a `provider` column to the log table — applied automatically on update.

= 1.0.29 =
Fixes (1) stray gray "pill" elements rendering on the What's New tab — a layout glitch introduced in 1.0.28 where literal `<tag>` text inside changelog bullets was interpreted as real HTML — and (2) the WordPress 6.7+ "Translation loading triggered too early" notice caused by translating the cron schedule's display label. Recommended upgrade for all 1.0.28 users.

= 1.0.28 =
UX polish release. Test send shows full provider response inline (with Copy button). HTTPS warning on webhook URL fields. "Welcome" admin notice after update points to the What's New tab. Failure-alert rate limiting (5-min default window per channel) prevents flood pings during burst failures. Plus a new CHANGELOG.md with the complete full-detail release history.

= 1.0.27 =
Small security + privacy release. Adds `manage_options` capability checks to log bulk-delete and queue retry/delete actions (defense-in-depth). Email Log now stores only attachment filenames instead of full filesystem paths to prevent server-layout leakage. No breaking changes.

= 1.0.26 =
Attachments and multipart_text now work in API mode for all 18 supported providers — 1.0.25 covered SES and Gmail, this release adds the remaining 16. Email Queue now records real provider error messages on failed sends (was a generic message), gets a "Process Queue Now" button, and test sends correctly bypass the queue. Plus a new "What's New" admin tab combining the roadmap with a collapsible release-history accordion. No breaking changes.

= 1.0.25 =
Adds attachment support for Amazon SES API mode (previously dropped silently — affected WooCommerce PDF invoices and any plugin-attached files). Also enables the "Multi-Part Plain Text" setting for SES and Gmail API modes (deliverability improvement) and adds RFC 2047 encoding for non-ASCII subjects and sender names. Recommended upgrade if you use SES API mode or send email in non-English languages.

= 1.0.24 =
**Critical OAuth fix.** Resolves the persistent `AADSTS50011` / redirect URI mismatch error when connecting Microsoft 365 or Gmail — the authorize URL was being built without URL-encoding the redirect_uri value, so Microsoft / Google saw it truncated at the first `&`. Strongly recommended upgrade if you use OAuth providers. Also: "Connect with provider" now opens in a popup window so you don't lose your settings page (falls back to full-page redirect when popups are blocked).

= 1.0.23 =
Fixes intermittent Microsoft 365 / Gmail OAuth `AADSTS50011` redirect URI mismatch errors caused by third-party security/caching plugins filtering `admin_url`. Also: Email Log "Next run" timestamp respects your site's date/time format, and the channel-logo SVG attribute whitelist is hardened. Recommended upgrade if you use OAuth (Gmail or M365).

= 1.0.21 =
Email Log gets a "Clean Now" button and an at-a-glance auto-clean status row. Routed emails now show the matching rule in the log. Routing rules pointing at deleted connections now show a warning. Real brand logos for Slack/Discord/Teams/Telegram/Google Chat/Pushover/Webhook on the Alerts tab. Fixes a rare race where saving the Summary Email form could wipe alert channels.

= 1.0.20 =
Fixes admin top-bar layout issues at narrow widths — overlap with the WP admin bar, oversized top gap, and horizontal scroll on mid-size screens.

= 1.0.19 =
Adds Smart Routing Rules — route emails through different connections based on recipient, source plugin (WooCommerce / Contact Form 7 / WPForms / etc.), subject, time, and more. Existing setups keep working unchanged.

= 1.0.18 =
Fixes a false-positive "Connected" indicator on the OAuth panel for Gmail / Microsoft 365 connections.

= 1.0.17 =
Minor data-consistency fix on top of v1.0.16's OAuth release. Safe upgrade.

= 1.0.16 =
Major UX upgrade for Gmail and Microsoft 365: one-click "Connect with provider" OAuth buttons replace the manual refresh-token workflow. Existing setups keep working.

= 1.0.15 =
Provider audit + Moosend HTML rendering fix. Recommended for everyone, especially Moosend users.

= 1.0.14 =
Reliability fix for the Email Queue: rows orphaned in "processing" status by a crashed cron run are now auto-recovered on the next run. Recommended for everyone using the queue.

= 1.0.13 =
Security release: hardens the PHP-mail and SMTP fallback paths against header-injection and path-traversal attacks from malicious upstream wp_mail filters. Sanitizes the fallback-connection label on read.

= 1.0.12 =
Renames "Default Connection" to "Primary Connection" in the admin UI. Fixes the fallback flow so `wp_mail()` returns true when the fallback succeeds, with a clear test-email message naming both connections. Provider status dot is now green/red based on configuration.

= 1.0.11 =
Cleans up how the plugin appears on the WordPress admin Plugins page. The big bold title and description column are no longer cluttered with the long SEO string.

= 1.0.10 =
Activates two previously-orphaned settings (Developer Debug, Max Retry Attempts) by adding their UI controls. Replaces every native <select> with a fully-styled brand-coloured dropdown component. Hardens form validation.

= 1.0.9 =
Refined the WordPress.org listing title to surface "SMTP" inside the brand for better directory search visibility. No code-level changes; in-product branding is unchanged.

= 1.0.8 =
Adds real automatic fallback connection logic — when your primary mail send fails, SendForce retries via the fallback connection automatically. Works across any combination of SMTP and API providers.

= 1.0.7 =
SEO-focused release: updated the public WordPress.org display name to match common SMTP / email-API search terms. Polished connection action buttons. No functional changes.

= 1.0.4 =
WordPress.org compliance release: comprehensive External Services documentation, Chart.js 4.5.0, removed inline scripts/styles, surfaced real provider error messages, hardened secret redaction.

= 1.0.3 =
Developer-focused release: WP-CLI commands, action/filter hooks, WP_DEBUG_LOG mirroring, raw API request/response capture, log export (CSV/JSON), and a "Copy Debug Info" button for support tickets.

= 1.0.1 =
Bug fixes, 5 new providers (SendLayer, Mailjet, MailerSend, Mandrill, Resend), Microsoft 365 & Gmail API support, new notification channels, and provider logos.

= 1.0.0 =
Initial release of SendForce Mail Relay.
