=== Kawaa Email Verification ===
Contributors: kawaa
Tags: email verification, email validation, contact form 7, woocommerce, disposable email
Requires at least: 5.0
Tested up to: 7.1
Stable tag: 1.0.11
Requires PHP: 7.4
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Checks the email addresses typed into your WordPress forms with the Kawaa API and turns away invalid and disposable ones before the form is sent.

== Description ==

Kawaa Email Verification checks each email address a visitor types into a form on your site as they fill it in, and stops the form from going through with an address that cannot receive mail. Forms from the supported form plugins are checked again by your server when they are submitted, so the check holds even when the visitor's browser skips the page's script.

The checks are made by [Kawaa](https://kawaa.com), an email verification service, so the plugin needs a Kawaa account and an API key. Each new address it checks uses credits from that account (see the FAQ for what that costs). Your API key stays on your server: visitors' browsers ask your own site, and your site asks Kawaa.

**What it can turn away:**

* **Invalid addresses** - addresses at domains that do not exist or do not accept mail, and mailboxes Kawaa found do not exist
* **Disposable addresses** - temporary, throwaway inboxes (on by default)
* **Role addresses** - generic addresses such as info@ and support@ (off by default)
* **Low-quality addresses** - anything Kawaa scores below the minimum quality score you set, except an address Kawaa could not reach a verdict on
* **Typo suggestions** - when Kawaa lets an address through but thinks its domain is misspelled, the message offers the correction ("Did you mean ...?") and the visitor can click it to use it. It is not shown for an address the plugin turns away: an address at gmial.com, which Kawaa rates invalid, gets the Invalid message

If Kawaa cannot be reached or cannot decide, the form goes through: the plugin never blocks a visitor because of a problem on Kawaa's side.

**Forms it checks:**

* Contact Form 7
* WPForms
* Gravity Forms
* Elementor Pro forms
* WooCommerce (classic checkout, registration and account details; the Checkout block is not supported yet)
* Native HTML forms (any email field: type=email, autocomplete=email, or marked with data-kawaa)

**What you control:** when the check runs (when the visitor leaves the field, as they type, or on submit), which of the above to turn away, a daily limit on how many addresses the site sends to Kawaa, which form plugins are checked, and every message visitors see.

== Installation ==

1. Upload the plugin files to the `/wp-content/plugins/kawaa-email-verification` directory, or install the plugin through the WordPress plugins screen directly.
2. Activate the plugin through the 'Plugins' screen in WordPress.
3. Go to Settings > Kawaa.
4. Enter an API key made for this site (see "How do I get an API key?") and save.
5. Click Test API Connection to check the key.

== External services ==

This plugin relies on the Kawaa email verification API, a third-party service run by Kawaa at https://api.kawaa.com, to check email addresses. Nothing is sent to it until you save a Kawaa API key under Settings > Kawaa, and visitors' addresses are sent only while Enable Verification is on (the default).

Your site's server makes these requests, never a visitor's browser, and each one carries your API key. WordPress sends its usual User-Agent header with them, which includes your site's address.

* **Checking an address** (POST https://api.kawaa.com/v1/verify). Sent when a visitor enters an email address in a form the plugin checks: when they leave the field, as they type, or when they submit, as set under Validate On. For forms from the supported form plugins it is sent again when the form is submitted, unless the same browser had that address checked in the last 24 hours. The request holds the email address the visitor typed and nothing else from the form. It is not sent for an address your site's code exempts with the kawaa_skip_verification filter, or once the site's Daily Verification Limit is reached.
* **Reading a check that is still running** (GET https://api.kawaa.com/v1/jobs/{id}). When Kawaa needs a few more seconds for an address, the plugin asks again for that check's result. The request holds only the check's ID.
* **Test API Connection** (GET https://api.kawaa.com/v1/account). Sent only when an administrator clicks Test API Connection under Settings > Kawaa. It sends nothing but the API key; Kawaa answers with your plan and credit balance.

Kawaa's terms of service: https://kawaa.com/terms/
Kawaa's privacy policy: https://kawaa.com/privacy/

== Frequently Asked Questions ==

= Do I need a Kawaa account, and what does it cost? =

Yes. The plugin is free, and the checks it makes use credits from your Kawaa account. A free Kawaa account comes with 100 credits when you sign up; they are not renewed each month. After that, either buy a credit pack, from 1,000 credits for $5 to 100,000 credits for $250, whose credits do not expire and which needs no subscription, or subscribe to a monthly plan, from $19 a month for 5,000 credits. Prices are in US dollars; [kawaa.com/pricing](https://kawaa.com/pricing/) lists every plan and pack.

= How do I get an API key? =

Sign up for free at [app.kawaa.com](https://app.kawaa.com), then create a key just for this site under [Settings > API keys](https://app.kawaa.com/settings/api-keys/?preset=custom). Under "What this key can do", choose Custom and tick only verification:write and account:read. The plugin uses verification:write to check addresses and account:read for Test API Connection. A key with only these cannot change your settings, billing, team or keys. It can still spend your credits and read your verification results (verification:write includes verification:read), your balance and your notifications, so keep it secret and revoke it if the site is compromised. (The AI agent preset also works; it adds analytics:read, which the plugin does not use.)

= How many credits does each verification use? =

Each fresh verification uses 1 credit (0.5 when Kawaa answers from its own cache). The plugin keeps each result on your site for 24 hours per browser, so when a visitor's browser has checked an address in the page, the check when they submit the form uses no credits. To tell browsers apart, the plugin's script sets a cookie, __Host-kawaa_vid, holding a random value, just before the visitor's first check, and renews it at each later check, so it lasts one day from the browser's most recent check; results are never shared between browsers. The cookie needs HTTPS. Without it (a site served over plain HTTP, or a browser that refuses the cookie), the in-page check uses 1 credit per address each time the page is loaded, and the check when the form is submitted uses another.

= Can visitors run up my credit usage? =

The in-page check only answers requests carrying a page nonce from your site, each visitor IP address gets 10 checks a minute, and Settings > Kawaa > Usage Limits > Daily Verification Limit (default 100) caps how many addresses the site sends to Kawaa per day. Past the limit, addresses are accepted without a check until the next day.

= My site is behind a proxy or CDN =

By default the per-visitor limit counts the address of the direct connection (REMOTE_ADDR), which behind a proxy is the proxy's. Choose the header your proxy sets under Settings > Kawaa > Usage Limits > Visitor IP Address. Only do this if all traffic reaches your site through that proxy: visitors can send these headers themselves.

= Does it work with my form plugin? =

The plugin supports Contact Form 7, WPForms, Gravity Forms, Elementor Pro forms, WooCommerce, and native HTML forms. You can enable/disable each integration in settings.

= Can I customize the error messages? =

Yes. Go to Settings > Kawaa > Custom Messages to customize all validation messages.

= What happens if the API is unavailable? =

If the API is unavailable, form submission will proceed normally. We never block legitimate users due to API issues. The same goes for an address Kawaa could not reach a verdict on (unknown): the Minimum Quality Score does not apply to it, and the form goes through.

= What does the minimum quality score do? =

An address Kawaa scores below it (default 50) is turned away with the Risky message, whatever its verdict, except unknown. Kawaa gives catch-all and risky addresses scores up to 60, so a higher minimum turns more of them away.

= What can a visitor see? =

The in-page check answers the visitor with the verdict for the address they typed (valid, invalid, risky and so on), its quality score, whether it is disposable or a role address, and a spelling suggestion. Nothing about your Kawaa account (credits, balance, request IDs) and no error text from Kawaa reaches the visitor.

= Can I skip the check for some addresses? =

Yes, with a few lines of PHP in your theme or a small plugin. A kawaa_skip_verification filter that returns true accepts an address without checking it, so it uses no credits. There is also a kawaa_verification_result filter, which can change a verdict, and kawaa_before_verify and kawaa_after_verify actions. The README.md file in the plugin's folder has examples. Base a skip on the address itself, such as its domain, because any visitor can tell a skipped address from a checked one.

= Does it work with full-page caching? =

Exclude pages with a checked form from your full-page cache, or keep cached copies younger than 12 hours. The in-page check sends a WordPress nonce that is part of the page and expires after 12 to 24 hours. With an expired one, the in-page check fails and lets the visitor carry on: a native HTML form is then sent without a check, and a form from one of the supported form plugins is checked only when it is submitted.

== Screenshots ==

1. Settings > Kawaa: the API key, and the daily limit that caps how many addresses visitors' checks can send to Kawaa.
2. The rest of the settings: what to turn away, which form plugins to check, and the messages visitors see.
3. Contact Form 7: an address at a domain that does not exist is turned away before the form is sent.
4. A plain HTML form: a misspelled address (gmial.com) is turned away as soon as the visitor leaves the field.

== Changelog ==

= 1.0.11 =
* The plugin's cookie, __Host-kawaa_vid, is renewed at each check, so it lasts one day from the visitor's most recent check. It used to run out one day after the first check, even for a visitor who was still using the form: the submission after a check made late in that day was then checked and paid for again, and so was asking again about an address Kawaa had not finished checking

= 1.0.10 =
* Tested with WordPress 7.1
* No more "Translation loading for the kawaa-email-verification domain was triggered too early" notice on WordPress 6.7 and later. With WP_DEBUG on it was shown on every page, and with WP_DEBUG_DISPLAY on it could break the redirect after logging in
* The Contact Form 7 check takes the address from Contact Form 7's submission, and the WooCommerce account details check from the account data WooCommerce has checked, instead of reading the request itself
* The plugin no longer loads its translations itself: WordPress loads them

= 1.0.9 =
* When Kawaa needs a few more seconds to check an address, the in-page check waits for that answer without paying again. Before this release, on a site served over plain HTTP or for a visitor whose browser refuses the plugin's cookie, the page asked again up to five times and each time used another credit, so one address could use six

= 1.0.8 =
* The developer hooks described in the README now work: kawaa_skip_verification, kawaa_verification_result, kawaa_before_verify and kawaa_after_verify. Before this release the plugin never ran them, so code written to skip the check for some addresses did not skip it
* Test API Connection says your credit balance is unavailable when Kawaa does not report it, instead of showing a balance of 0

= 1.0.7 =
* The in-page check tells visitors only the verdict for their address. It no longer passes on your credit balance, request IDs, or when Kawaa last checked the address, and shows no error text from Kawaa
* The minimum quality score no longer turns away addresses Kawaa could not reach a verdict on (unknown). Other addresses below it get the Risky message instead of Invalid email address
* Only email fields are checked: type=email, autocomplete=email, or marked with data-kawaa. Hidden inputs, checkboxes and other fields with "email" in their name no longer block the form
* The first click on Submit after typing an address is no longer lost
* Deleting the plugin now removes its settings (your API key included) and its cached results

= 1.0.6 =
* Fix WPForms submit-time verification with WPForms' three-argument email validation hook

= 1.0.1 =
* The in-page check only answers requests carrying the page's nonce
* The per-visitor limit counts the connection's address; a proxy header is used only when chosen under Usage Limits
* New Daily Verification Limit (default 100) caps the credits the plugin spends per day
* Submit-time checks reuse the page's result for the same browser, so one signup costs one credit

= 1.0.0 =
* Initial release
* Real-time email verification
* Support for major form plugins
* Customizable messages and styling
* JavaScript API for developers

== Upgrade Notice ==

= 1.0.11 =
Keeps a returning visitor's checks paid for once: the plugin's cookie now lasts one day from the visitor's most recent check instead of one day from the first.

= 1.0.10 =
Tested with WordPress 7.1. Stops the "Translation loading ... triggered too early" notice WordPress 6.7 and later showed on every page with WP_DEBUG on.

= 1.0.9 =
Stops the in-page check using up to six credits for one address when Kawaa takes a few seconds to answer and the visitor's browser does not have the plugin's cookie, for example on a site served over plain HTTP.

= 1.0.8 =
The developer hooks in the README now run. If your site has code that uses kawaa_skip_verification, kawaa_verification_result, kawaa_before_verify or kawaa_after_verify, it takes effect from this version, so check it. Test API Connection no longer shows a balance of 0 when the balance is unknown.

= 1.0.7 =
Stops the in-page check telling visitors about your Kawaa account, stops rejecting addresses Kawaa could not reach a verdict on, and stops opt-in checkboxes and other non-address fields from blocking forms.

= 1.0.1 =
Stops visitors spending your Kawaa credits without limit. Adds a daily limit (default 100); raise it under Settings > Kawaa > Usage Limits if your site takes more signups.

= 1.0.0 =
Initial release of Kawaa Email Verification for WordPress.
