=== 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: smtp, wp smtp, email log, mailer, email api
Requires at least: 5.9
Tested up to: 6.9
Stable tag: 1.0.20
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.
* **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 ==

= 1.0.20 =
* Fix: Admin top navigation bar layout at narrow widths — resolved overlap with the WordPress admin bar on tablet/mobile, removed an oversized empty gap above the SendForce header, and prevented horizontal page scroll when tab labels would otherwise overflow on mid-size laptop screens.
* Tweak: Tab labels now collapse to icon-only mode below 1340px (was 1180px) so all tabs fit cleanly without scrolling on common laptop widths.
* Tweak: Logo gets proper left breathing room on mobile — no more flush-to-edge.

= 1.0.19 =
* New: **Smart Routing Rules**. Send different emails through different connections based on rules you define. Conditions: recipient domain, recipient pattern (glob), 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, weekday. Rules evaluated top-down — first match wins. If no rule matches, the email goes through your Primary connection (existing behaviour preserved).
* New "Routing" tab in the admin (sidebar submenu) with rule list, per-rule add / edit / delete, enable/disable toggle, and a built-in "Test Routing" tool that lets you paste a sample recipient + subject + source plugin and see exactly which rule (if any) would fire and which connection would be used.
* The mailer now always registers BOTH the API send filter and the SMTP `phpmailer_init` action and lets the (possibly routed) settings choose the path. This means a routing rule can freely switch between API and SMTP target connections — e.g. primary SMTP → routed to SES API, or primary API → routed to a different SMTP server.
* Storage: new `wp_sendforce_routes` table (added automatically on plugin upgrade via dbDelta). The routes table is now self-healing — if it's ever missing on an admin page load, it's recreated immediately.
* New: **inline rule editor**. Routing rules are now edited directly on the page as expandable cards — no modal popups. See all rules and conditions at a glance, edit any field inline, with an "Unsaved changes" indicator and Revert button per rule.
* New: **master "Enable Smart Routing" toggle** at the top of the Routing tab. Lets you pause all rules without deleting them — useful for diagnosing whether routing is involved in an issue.
* New: **`from_email` and `from_domain` condition types** — match by sender address, not just recipient. Useful when a single site sends from multiple identities (shop@, support@, noreply@).
* New: **matched rule shown in Email Log**. When a routing rule redirects an email, the log entry now displays a "via rule: <label>" badge under the subject so you can see exactly which rule fired for any given send.
* New: **starter presets** in the empty state — one-click rules for WooCommerce orders, @gmail.com recipients, and contact form submissions.
* New: **"What's Next" / Roadmap tab** in the admin — public roadmap of upcoming features, grouped by release.
* New: **styled confirm/alert dialogs** replace native browser pop-ups across the routing UI for a consistent look.
* Improvement: better keyboard support and focus management for routing dialogs (Esc to cancel, Enter to confirm).
* Improvement: navigation collapses to icon-only buttons on medium-width screens so all tabs fit cleanly without overflow.

= 1.0.18 =
* Fixed a misleading "Connected" status on the Gmail / Microsoft 365 OAuth panel. The panel previously showed "Connected" (green) whenever the connection's password field had any value — including when the value was a leftover SMTP password from a previous SMTP-mode setup or a refresh token without matching Client ID / Secret. The check is now strict: green "Connected" only renders when the connection is in API mode AND a Client ID is present AND a Client Secret is stored AND a refresh token is stored.
* Added a new amber state — "Connection has a stored OAuth token but the Client ID or Client Secret is missing. Re-enter your OAuth credentials and click Reconnect." — for the partial-credentials edge case (only fires in API mode, so an SMTP password is never mistaken for an orphaned OAuth token).
* The OAuth panel now shows a friendly "Switch the connection to API mode above to use OAuth" hint when a Gmail / Microsoft 365 connection is still in SMTP mode.
* Polished the OAuth status indicator dot — larger (12px), stronger glow, properly aligned with the first line when the status text wraps to multiple lines, deeper text colours for better contrast.

= 1.0.17 =
* Initialize the `oauth_email` field on newly created connections so the schema is consistent from the moment a connection is saved (was previously added only after the first OAuth completes — defensive code in JS handled the missing key, but the data shape was inconsistent).

= 1.0.16 =
* New: **One-click "Connect with Google" and "Connect with Microsoft" OAuth buttons** for the Gmail and Microsoft 365 connections. Replaces the previous (very painful) workflow of generating refresh tokens manually via OAuth Playground or Azure CLI. The user pastes their Client ID + Client Secret once, clicks Connect, signs in, grants consent, and is done.
* The OAuth refresh token is captured automatically and stored encrypted in the connection. The connection panel shows "Connected as user@example.com" with a Disconnect button. No third-party OAuth proxy involved — bring-your-own-credentials model, every site retains full control of its own Google Cloud / Azure AD app.
* Microsoft 365: the API now supports **both delegated (authorization_code) and app-only (client_credentials) flows**, picked automatically based on whether a refresh token is stored. Existing Application-permission setups keep working unchanged.
* Setup help panel inline in the connection form: step-by-step instructions for creating the Google Cloud / Azure AD app, plus the exact redirect URI to register, with a click-to-select copy box.

= 1.0.15 =
* Audited all 20 provider integrations (SendGrid, Mailgun, Brevo, SparkPost, Postmark, Amazon SES, Elastic Email, SMTP2GO, Pepipost/Netcore, SMTP.com, SocketLabs, Moosend, Microsoft 365, Gmail, SendLayer, Mailjet, MailerSend, Mandrill, Resend, Zoho ZeptoMail) against current provider documentation. 18 of 20 verified spec-compliant; 1 minor fix below.
* Fixed Moosend HTML content-type detection. The Moosend API treats an unset `IsContentHtml` flag inconsistently — now set explicitly in BOTH HTML and plain-text paths so the rendering matches what the user sent. Previously HTML emails sent via Moosend could render as plain text in some accounts.

= 1.0.14 =
* Fixed an Email Queue bug where rows that entered "processing" state and then never completed (because the cron run timed out, the PHP process crashed, or the server restarted mid-batch) became orphaned forever. Each row claimed by the processor now carries a 10-minute lease (stored in `next_retry_at`); on the next cron run any rows whose lease has expired are automatically returned to the queue and retried.

= 1.0.13 =
* Security: hardened the PHP-mail fallback path against header injection. Carriage-return / line-feed / null characters are now stripped from the To, Subject and every individual header line before being passed to mail(), preventing a malicious wp_mail filter from injecting BCC / CC / spoofed headers via embedded newlines.
* Security: validated attachment paths in the SMTP fallback path. Attachments are now only added when the resolved path lies inside a known-safe root (ABSPATH, WP_CONTENT_DIR, WP_PLUGIN_DIR, the uploads directory, or the system temp dir), preventing a path-traversal attack from a malicious upstream filter that could otherwise read arbitrary OS files.
* Security: sanitized the fallback-connection label on read with `sanitize_text_field()` so any HTML stored in the option (by any means) cannot leak into admin UI surfaces.
* Defense-in-depth: provider error messages echoed back into the test-email response are now run through `wp_strip_all_tags()` before being sent to the browser. The client already renders them via `.text()` so XSS was already blocked, but stripping tags server-side keeps the audit trail clean.

= 1.0.12 =
* Renamed "Default Connection" to "Primary Connection" throughout the admin UI for clearer terminology (the connection-row badge, the General Settings section heading, helper text, and the About page). The internal storage key remains `default_connection` so existing user data is preserved without migration.
* Provider status dot on the Email Test page now reflects the connection STATUS (green when configured, red when not) rather than the provider's brand colour. Fixes the misleading red dot next to providers like Google and Mailgun whose brand happens to be red.
* Fixed the fallback-connection flow so `wp_mail()` correctly returns `true` when the primary fails but the fallback succeeds. The test-email UI now shows a clear "Test email sent via the fallback connection (X). The primary connection (Y) failed; the fallback recovered the send." message instead of misleading the user with the primary failure.
* Suppressed the "WARNING: SMTP connection may not have completed properly" message when the active send path was API or PHP-Mail (it never applied to those modes; it was firing incorrectly).

= 1.0.11 =
* Fixed cluttered display on the WordPress admin Plugins page. The `Plugin Name:` header is now the clean brand name "SendForce Mail Relay" (was the long SEO title), and the `Description:` header is a single-line summary instead of the full provider list. The long SEO title remains on the WordPress.org directory listing page for search visibility.

= 1.0.10 =
* Added a UI control for the **Developer Debug** setting in Settings → Queue & Logging. Previously the value was honored by the mailer code but had no admin toggle.
* Added a UI control for **Max Retry Attempts** (1–10) in the Email Queue section. Previously the queue read this value but there was no field to set it.
* Hardened settings sanitization: the From Email field is now rejected with an admin notice when it isn't a valid email (instead of being silently truncated). Batch Size and Max Retry Attempts are now clamped to their valid ranges server-side.
* Replaced every native <select> dropdown with a fully-styled custom component. The open menu is now properly themed in the SendForce brand teal (animated panel, brand-color selected state, scroll-on-overflow, custom checkmark on the active item) instead of falling back to the OS-native menu that browsers refuse to style. Original <select> elements are kept hidden in the DOM so form submission, "change" event listeners, and screen readers all keep working unchanged.
* Full keyboard support on the new dropdown: ArrowUp/ArrowDown to navigate, Enter to select, Escape to close, click-outside to dismiss.
* Default and Fallback connection selectors automatically refresh after adding or saving a connection (the styled UI gets the new option immediately, no page reload needed).
* Polished form-control styling: cleaner chevron arrow, brand-teal focus ring, hover state on the arrow icon, and disabled state for inputs and selects. Edit row buttons now use the brand teal on hover (was indigo).

= 1.0.9 =
* Tweaked the WordPress.org listing title to "SendForce Mail SMTP Relay — Free WP SMTP & Email API Plugin for Amazon SES, SendGrid, Mailgun, Brevo, Postmark, Zoho ZeptoMail & Gmail" so the SMTP keyword sits inside the brand cluster for better directory search matching. The internal product brand remains "SendForce Mail Relay" everywhere users see it (page titles, About page, alerts, email subjects).

= 1.0.8 =
* New feature: **Automatic fallback connection.** The fallback dropdown in Settings → Connections is now wired to real send logic. When the primary connection's send fails, SendForce immediately retries via the configured fallback connection — works across any combination of API → API, API → SMTP, SMTP → API, SMTP → SMTP, or any → PHP mail.
* The original failed attempt is still recorded in the Email Log; if the fallback succeeds, a second "sent" log row is created with a "Recovered via fallback connection" badge so you have a complete audit trail.
* Refactored connection resolution into a shared `merge_connection_into()` helper; reduces duplication and makes the fallback path use the exact same config-merge rules as the primary.
* Improved long-form Description in readme for better WordPress.org discoverability (added "Why SendForce", reorganized provider list by API vs SMTP, added "Works with all major WordPress plugins" section listing WooCommerce, Contact Form 7, WPForms, Gravity Forms, Elementor Forms, MemberPress, LearnDash, BuddyPress and more).

= 1.0.7 =
* Updated the public plugin display name to "SendForce Mail SMTP — Free WP SMTP & API Plugin for Amazon SES, SendGrid, Mailgun, Brevo, Postmark, Zoho ZeptoMail & Gmail" so the WordPress.org search index correctly matches users looking for SMTP / API integrations with these specific providers. Internal slug, code, classes, and admin sidebar label are unchanged.
* Rewrote the short description and `Description:` plugin header for better discoverability.
* Refreshed the readme `Tags` to the highest-volume search terms in this category (smtp, wp smtp, email log, mailer, email api).
* Polished the connection-row Edit / Delete buttons with dashicons, hover states, and proper destructive styling for the delete action.
* Added sub-menu entries (Dashboard, Settings, Email Log, Email Queue, Email Test, Alerts) under the SF Mail Relay sidebar item, plus a `submenu_file` filter so the active tab is highlighted correctly when deep-linked.

= 1.0.6 =
* Shortened the WordPress admin sidebar label from "SendForce Mail Relay" to "SF Mail Relay" so it fits on a single line. The full plugin name is preserved everywhere else (page title, dashboard widget, alerts, email subjects).
* Added sub-menu entries under SF Mail Relay — Dashboard, Settings, Email Log, Email Queue, Email Test, Alerts — so each tab is reachable directly from the sidebar fly-out.

= 1.0.5 =
* Removed an accidentally bundled macOS `.DS_Store` file from `assets/images/providers/`.
* Added explicit `phpcs:ignore` annotations with rationale to four `$wpdb` queries in `includes/class-sendforce-cli.php` and `includes/class-sendforce-sysinfo.php` where the table name is interpolated from `$wpdb->prefix` plus a hardcoded literal (no user input).
* Restructured the WP-CLI `log delete --before` query onto a single line so the existing `phpcs:ignore` directive correctly suppresses the `InterpolatedNotPrepared` warning on the prepared inner statement.

= 1.0.4 =
* Updated bundled Chart.js from 4.4.0 to 4.5.0.
* Rewrote the External Services section in readme.txt to fully document every email provider, notification channel, and bundled library — including SendLayer, MailerSend, Mailjet, Mandrill, Resend, Zoho ZeptoMail, Microsoft 365 Graph, Gmail API, Telegram, Pushover, Slack, Discord, Microsoft Teams, Google Chat, and Custom Webhook — with verified privacy and terms-of-service URLs for each.
* Removed all inline `<style>` and `<script>` blocks from PHP output. Conflict-detection notice CSS and JS are now in dedicated assets/css/conflict-notice.css and assets/js/conflict-notice.js, properly enqueued via wp_enqueue_style/script. Alerts tab JS bootstrap data now uses wp_add_inline_script.
* Surface the actual provider HTTP status and response body in the failure error so users can diagnose API errors instead of seeing only a generic "Failed to send" message.
* Added a "Raw API request / response" panel to the Email Log detail modal — shows the captured (and secret-redacted) request/response from the last attempt.
* Show masked dots (••••••••••••••••) as the placeholder for SMTP Password and API Key fields when a value is already saved, so the field no longer looks empty.
* Hardened secret redaction: response bodies are now redacted (some providers echo the request payload back in errors); the redactor also handles malformed/non-JSON bodies via a regex fallback and includes `client_secret` in the secret-key list.
* Defused CSV formula injection on log export and added the explicit fputcsv escape argument for PHP 8.1+.
* Gated the on-load DB schema upgrade routine to admin / WP-CLI context only.
* Added confirmation prompts to the destructive WP-CLI commands `wp sendforce queue clear` and `wp sendforce log delete`.

= 1.0.3 =
* Added WP-CLI commands: `wp sendforce test`, `wp sendforce queue process|stats|clear`, `wp sendforce log list|tail|delete|count`, `wp sendforce sysinfo`.
* Added developer hooks: `sendforce_before_send`, `sendforce_after_send`, `sendforce_log_entry` filter, `sendforce_api_request`, `sendforce_api_response`.
* Added "Developer debug" setting to mirror SMTP and API debug output to `debug.log` (requires WP_DEBUG_LOG).
* Added raw API request/response capture stored in a new `debug_data` log column (Authorization headers redacted).
* Added Email Log export as CSV or JSON, honoring active filters.
* Added "Copy Debug Info" button on the Email Test screen — generates a sanitized environment + settings snapshot with secrets stripped.
* Replaced stale "SMTP-Manager" User-Agent on Resend API requests with "SendForce-Mail-Relay".
* Added one-time DB upgrade routine to add the `debug_data` column on existing installs.

= 1.0.1 =
* Fixed conflict detection banner not showing on all admin pages.
* Fixed test email branding from "SMTPFlow" to "SendForce Mail Relay".
* Added Microsoft 365 Graph API and Gmail API support.
* Added 5 new providers: SendLayer, Mailjet, MailerSend, Mandrill, Resend.
* Added Zoho ZeptoMail API support.
* Added 3 new notification channels: Microsoft Teams, Google Chat, Custom Webhook.
* Added SVG provider logos for all providers.
* Added collapsible provider grid with smooth animation.
* Fixed API mailer bugs: SendLayer field names, Pepipost endpoint, SparkPost CC, SES BCC, MailerSend Reply-To.
* Added CC/BCC/Reply-To support to Elastic Email, SMTP2GO, SMTP.com, SocketLabs, Moosend, Pepipost.
* Auto-set first connection as Default Connection.
* Bundled Chart.js locally (removed CDN dependency).
* Fixed all WordPress Plugin Check errors and warnings.
* Renamed main plugin file to sendforce-mail-relay.php.

= 1.0.0 =
* Initial release.
* SMTP configuration with 18 provider presets and one-click setup.
* HTTP API sending support for 12 providers (SendGrid, Mailgun, SES, Brevo, SparkPost, Postmark, Elastic Email, SMTP2GO, Pepipost, SMTP.com, SocketLabs, Moosend).
* From name and email override for all outgoing WordPress emails.
* Full email logging with keyword search, status filter, and date range filter.
* Email queue with WP-Cron processing and exponential backoff retry.
* Dedicated Email Test page with live SMTP debug log.
* Encrypted password and API key storage (AES-256-CBC).
* Auto log cleanup with configurable retention period.
* Modern admin dashboard with connection status and 7-day send chart.

== Upgrade Notice ==

= 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.
