=== Rewind Form Bridge for Brevo ===
Contributors: jakirulislambd19
Tags: brevo, smtp, newsletter, email-marketing, form-submissions
Requires at least: 6.6
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.0.0
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Send your site's email through Brevo SMTP, and add every form submission to a Brevo contact list automatically.

== Description ==

Two jobs, both done properly.

**Brevo SMTP, without a second plugin.** Point `wp_mail()` at Brevo and your
site's email — order receipts, password resets, form notifications — leaves
through an account that is actually allowed to send it, instead of your host's
unauthenticated `mail()`. Choose the Brevo API over HTTPS (works on hosts that
block outbound SMTP ports) or the classic Brevo SMTP relay. Off until you
switch it on, so installing this plugin never silently reroutes your mail.

**Every form submission becomes a Brevo contact.** Brevo's own plugin only
syncs contacts from Brevo's own sign-up forms — anything a visitor types into
WPForms, Formidable, Contact Form 7 or Forminator never reaches your lists.
Map a form to a Brevo list once, and from then on every submission is added
automatically, with the right values in the right contact attributes, a record
of the consent the visitor gave, and a log entry you can open when something
looks wrong.

**Disclaimer:** Rewind Form Bridge for Brevo is an independent, third-party plugin.
It is not affiliated with, endorsed by, or an official partner of Brevo
(Sendinblue SAS). "Brevo" and "Sendinblue" are trademarks of their respective
owner. This plugin simply connects to the publicly documented Brevo API using
an API key you create in your own Brevo account.

= What it does =

* **Brevo SMTP or Brevo API for site email.** One toggle, a sender address,
  and `wp_mail()` goes out through Brevo. Delivery failures are recorded and
  shown on the dashboard instead of vanishing. Optional and off by default.
* **Maps any field to any attribute.** Pick a form field, pick a Brevo contact
  attribute, done. No paywall on the mapping UI.
* **Type coercion that stops silent data loss.** Brevo accepts a request whose
  value does not match the attribute's declared type — and then quietly drops
  the value. No error, no warning, an empty field. This plugin validates and
  converts every value against the attribute's real type *before* sending, so a
  date lands as a date and a number lands as a number.
* **Phone numbers normalised to E.164.** Brevo rejects or mis-stores a bare
  local number. Set a default country and local numbers are converted to the
  international form Brevo expects.
* **Consent capture, on by default.** A feed will not send anything unless a
  consent checkbox is mapped and ticked. You can switch that off per feed, and
  the screen tells you plainly what you are switching off.
* **A real delivery log.** Every submission gets a row: status, HTTP code,
  Brevo's error code translated into a sentence a human can act on, and the
  exact request and response bodies. Retry a failed delivery from the log.
* **Failure alerts.** After a run of consecutive failures, an email goes out so
  a revoked API key does not silently swallow a month of sign-ups.
* **Never calls the API behind your back.** No request is made on activation,
  on admin page loads, or before you save a key. Lists and attributes are
  cached and refreshed only when you ask.

= Supported form plugins =

* WPForms (Lite and Pro)
* Formidable Forms (Lite and Pro)
* Contact Form 7
* Forminator

Each integration is written against that plugin's own submission hook, so
composite fields are handled properly: a WPForms, Formidable or Forminator
Name field exposes its first, middle and last parts as separate mappable
values, and Address fields expose street, city, state, postal code and
country. The adapter layer is public — additional form plugins can be added by
filtering `rbfb_adapters`.

= Your API key =

Brevo API keys are account-wide — Brevo does not offer scoped keys. The key is
stored in the options table, shown in the dashboard as its last four characters
only, and never included in a REST response, a log entry or an export. If you
would rather keep it out of the database entirely, define it in `wp-config.php`
and the field becomes read-only:

`define( 'RBFB_API_KEY', 'your-key-here' );`

== External Services ==

This plugin connects to Brevo, a third-party email marketing and transactional
email service, because sending your form submissions to Brevo is the entire
purpose of the plugin. No request is ever made until you enter your own Brevo
API key.

**Brevo API** — https://api.brevo.com/v3 (service homepage: https://www.brevo.com/)

What is sent, and when:

* When you click "Test connection": nothing but your API key, to
  `GET /account`, to confirm the key works and to read your account name.
* When you open the field-mapping screen and ask to refresh: your API key, to
  `GET /contacts/lists`, `GET /contacts/folders` and `GET /contacts/attributes`,
  to read back the lists and contact attributes in your account. Results are
  cached locally for 15 minutes.
* When you create a contact attribute from the mapping screen: the attribute
  name and type, to `POST /contacts/attributes/{category}/{name}`.
* When a visitor submits a form you have mapped: the submitted email address,
  the form values you mapped to Brevo attributes, and the IDs of the lists you
  chose, to `POST /contacts`.
* Only if you switch on "Site email": your API key, to `GET /senders`, to read
  back the verified sender addresses on your Brevo account so you can pick one.
* Only if you switch on "Site email" with the API transport: the recipients,
  subject and body of the emails your site sends via `wp_mail()`, to
  `POST /smtp/email`.

**Brevo SMTP relay** — smtp-relay.brevo.com

Only if you switch on "Site email" and choose the SMTP transport. Your SMTP
login, SMTP key, and the recipients, subject and body of each outgoing email
are sent to Brevo's relay over an authenticated TLS connection.

By using this plugin you are sending data to Brevo, and Brevo's own terms
govern that data:

* Terms of Service: https://www.brevo.com/legal/termsofuse/
* Privacy Policy: https://www.brevo.com/legal/privacypolicy/

The plugin makes no other outbound request. It contacts no analytics service,
no licensing server, and no CDN — fonts and scripts are all served from your
own site.

== Privacy ==

The plugin stores three tables in your own database: mapped feeds, a delivery
log (submitted values, request and response bodies, capped at 64KB each), and a
consent record (email address, the exact consent wording the visitor saw, the
page URL and the visitor's IP address).

Consent records exist so you can prove a subscription was asked for, which is
why nothing is deleted when you uninstall unless you first tick "Delete all
plugin data when the plugin is uninstalled" on the Settings screen. Log entries
can be cleared at any time from the Logs screen.

== Installation ==

= 1. Install the plugin =

From your WordPress admin, go to **Plugins → Add New**, search for "Rewind Form
Bridge for Brevo", click **Install Now**, then **Activate**.

To install the zip by hand instead: **Plugins → Add New → Upload Plugin**,
choose the file, **Install Now**, then **Activate**. Or unzip it into
`/wp-content/plugins/` over FTP so the files land in
`/wp-content/plugins/rewind-form-bridge-for-brevo/`, then activate it from the
Plugins screen.

You need WordPress 6.6 or newer and PHP 7.4 or newer. Nothing is sent to Brevo
during installation or activation.

= 2. Get a Brevo API key =

1. Sign in at https://app.brevo.com/ — a free account is enough.
2. Open https://app.brevo.com/settings/keys/api
3. Click **Generate a new API key**, name it something you will recognise later
   (for example "WordPress"), and copy the value. It starts with `xkeysib-`.
4. Copy it now: Brevo shows the key once and never again.

Brevo API keys are account-wide — Brevo offers no scoped or read-only keys, so
this key can do anything your Brevo account can do. Treat it like a password.

= 3. Connect =

Go to **Brevo Bridge → Connections**, paste the key, and click **Test
connection**. On success the screen shows your Brevo account name and the last
four characters of the key; the key itself is never shown again, never returned
by the REST API, and never written to the delivery log.

Prefer to keep the key out of the database? Put this in `wp-config.php`
instead, above the "That's all, stop editing" line:

`define( 'RBFB_API_KEY', 'xkeysib-your-key-here' );`

The field then shows as read-only and sourced from the constant.

= 4. Send your site's email through Brevo (optional) =

Skip this if you only want contact syncing.

1. In Brevo, add and verify the address you want to send from, under
   **Senders, Domains & Dedicated IPs**. Brevo rejects mail from an unverified
   sender, so do this first.
2. Go to **Brevo Bridge → Settings → Email** and switch **Site email** on.
3. Choose a transport:
   * **API (recommended)** — sends over HTTPS on port 443, which every host
     allows. Uses the API key you already saved.
   * **SMTP relay** — the classic route. You will also need your SMTP login and
     an SMTP key from https://app.brevo.com/settings/keys/smtp, and your host
     must allow outbound port 587, 465 or 2525.
4. Pick your verified sender address, and a reply-to address if it differs.
5. Click **Send test email** and confirm it arrives.

Until you complete this step `wp_mail()` behaves exactly as it did before —
installing the plugin does not silently reroute your site's email.

= 5. Send form submissions to a Brevo list =

1. Make sure the form plugin you use is active: WPForms, Formidable Forms,
   Contact Form 7 or Forminator.
2. Add a consent checkbox to your form if it does not have one — something like
   "Yes, email me your newsletter". You need it for step 5, and you need it to
   be able to show that each subscriber asked to be subscribed.
3. Go to **Brevo Bridge → Mappings** and click **Add mapping**.
4. Choose the form plugin, then the form, then the Brevo list or lists the
   contact should join.
5. Choose the **consent field** — the checkbox from step 2. Nothing is sent for
   a submission where that box was left unticked.
6. Choose the **email field**. This is the only mapping that is required.
7. Map any other fields you want on the contact. Each row pairs one form field
   with one Brevo contact attribute, and the screen shows the type Brevo
   expects for that attribute so values are converted correctly instead of
   being silently dropped. Name and Address fields can be mapped whole or by
   part — first name and last name to separate attributes, for example.
8. If you map a phone or SMS attribute, set **Default country** under
   **Settings → General** so local numbers are converted to the international
   form Brevo requires.
9. Save.

= 6. Check that it worked =

Submit the form on your site once, then open **Brevo Bridge → Logs**. You
should see a row with status **Success** and HTTP code 201 (contact created) or
204 (existing contact updated). Open the row to see the exact request that was
sent and the exact response Brevo returned.

If the row says **Failed**, the message column explains why in plain language,
and **Retry** re-sends that submission once you have fixed the cause. If it
says **Skipped**, the consent box was not ticked, or the contact already exists
and this mapping is set not to update existing contacts.

Optionally, set a **Failure alert email** under **Settings → General** so you
are told by email if deliveries start failing in a row.

== Frequently Asked Questions ==

= Do I need a paid Brevo account? =

No. A free Brevo account gives you an API key, and that is all this plugin
needs.

= Which form plugins are supported? =

WPForms, Formidable Forms, Contact Form 7 and Forminator — free editions
included. Each one is integrated through its own submission hook, so nothing
depends on scraping `$_POST`. The adapter layer is a documented filter
(`rbfb_adapters`), so more can be added without touching the core of the
plugin.

= Why is my contact created but a field is empty? =

That is Brevo's most confusing behaviour: if a value does not match the
attribute's declared type, Brevo accepts the request and silently drops the
value. This plugin coerces and validates every value before sending
specifically to prevent it, and the delivery log records any value it had to
convert or reject. If you still see an empty field, open the log entry — the
request body shows exactly what was sent.

= Why is my phone number rejected? =

Brevo requires a country code on SMS attributes. Set **Default country** on the
Settings screen and local numbers will be converted for you.

= Are any features locked behind a payment? =

No. Everything described here works in this plugin, with no licence key,
account or trial period.

= Does the plugin call Brevo when I am just clicking around the dashboard? =

No. Requests happen only when you test the connection, explicitly refresh the
cached lists and attributes, create an attribute, or when a visitor actually
submits a mapped form.

= Will installing this change how my site sends email? =

Not unless you tell it to. "Site email" is off by default; `wp_mail()` behaves
exactly as it did until you switch the transport on yourself.

= Should I use the Brevo API or the Brevo SMTP relay? =

Prefer the API. It rides HTTPS on port 443, which every host allows, while many
hosts block outbound 587 and 465 — and when they do, the symptom is simply that
email stops, with no error anywhere. Choose the SMTP relay only if your Brevo
account or hosting policy requires a real SMTP conversation.

= Do I still need a separate WP SMTP plugin? =

No. Switch on Site email, pick a verified Brevo sender, and this plugin takes
over `wp_mail()` for the whole site.

= Can I use this only for SMTP, without mapping any forms? =

Yes, and the reverse is also true. The two features are independent: the site
email transport works with no feeds configured, and contact sync works whether
or not you route your site's email through Brevo.

== Source Code ==

The admin dashboard is a React application compiled with `@wordpress/scripts`.
Everything in `assets/` is build output — `assets/admin.js`, its stylesheets,
and the hashed font files in `assets/fonts/`. The complete, unminified source
those are built from ships inside this plugin, in `src/`, including the
original font files in `src/admin/fonts/`. Nothing has to be downloaded to
inspect or rebuild it.

To rebuild from the plugin folder:

1. `npm install`
2. `npm run build`

That reads `src/admin/index.js` and rewrites `assets/`.

No minified or obfuscated third-party code is bundled. React, ReactDOM, the JSX
runtime and every `@wordpress/*` package are loaded from the copies WordPress
core already ships, declared as script dependencies in
`assets/admin.asset.php`.

== Credits ==

* Poppins by Indian Type Foundry and Jonny Pinhorn, licensed under the SIL Open
  Font License 1.1 (https://scripts.sil.org/OFL) and self-hosted.
* Portions of the React component kit are derived from Ninja Drive by
  Plugininja, licensed GPL-2.0-or-later.

See `LICENSE.txt` in the plugin folder for the full list of bundled assets and
their licences.

== Screenshots ==

1. The dashboard: connection health, recent deliveries and delivery counts.
2. Connections: paste a Brevo API key and test it without leaving the page.
3. Mappings: a WPForms field mapped to a Brevo contact attribute, with the type
   Brevo expects shown beside each one.
4. The delivery log: every submission, its status, and the Brevo error
   translated into a sentence.
5. A single log entry, showing the exact request and response bodies.
6. Settings: default country, log retention, failure alerts and data removal.
7. Settings → Email: routing the site's `wp_mail()` through Brevo, over the API
   or the SMTP relay.

== Changelog ==

= 1.0.0 =
* Initial release.
* Form integrations for WPForms, Formidable Forms, Contact Form 7 and
  Forminator: map any form to a Brevo list.
* Field mapping with type coercion and validation against each Brevo
  attribute's declared type.
* Phone normalisation to E.164 with a configurable default country.
* Consent capture, required by default, with a stored consent record.
* Delivery log with translated Brevo error codes, full request and response
  bodies, retry, and manual retention clearing.
* Email alerts after a run of consecutive delivery failures.
* Optional site email delivery through the Brevo API or the Brevo SMTP relay,
  replacing a separate WP SMTP plugin.
* `RBFB_API_KEY` constant support for keeping the key out of the database.

== Upgrade Notice ==

= 1.0.0 =
First public release.
