{"id":381944,"date":"2026-10-12T02:18:49","date_gmt":"2026-10-12T02:18:49","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/mailbag-contact-form\/"},"modified":"2026-10-12T02:18:14","modified_gmt":"2026-10-12T02:18:14","slug":"letterkeep-contact-form","status":"publish","type":"plugin","link":"https:\/\/en-ca.wordpress.org\/plugins\/letterkeep-contact-form\/","author":23560846,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.0","stable_tag":"1.0.0","tested":"7.1.3","requires":"6.5","requires_php":"7.4","requires_plugins":null,"header_name":"Letterkeep Contact Form","header_author":"WeCode","header_description":"A contact form that saves every entry in WordPress before it sends anything, and shows whether each email reached your mail server.","assets_banners_color":"717f7d","last_updated":"2026-10-12 02:18:14","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/letterkeepcontactform.pages.dev\/","header_author_uri":"","rating":0,"author_block_rating":0,"active_installs":0,"downloads":32,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"frostydev","date":"2026-10-12 02:18:14","revision":3740370}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3740370,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3740370,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3740370,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3740370,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":{"letterkeep\/form":{"$schema":"https:\/\/schemas.wp.org\/trunk\/block.json","apiVersion":3,"name":"letterkeep\/form","version":"1.0.0","title":"Letterkeep Form","category":"widgets","icon":"email-alt","description":"A contact form that saves every entry before it sends anything.","keywords":["contact","form","letterkeep","email"],"textdomain":"letterkeep-contact-form","attributes":{"formId":{"type":"number","default":0}},"supports":{"html":false,"align":["wide","full"]},"editorScript":"file:.\/editor.js"}},"tagged_versions":["1.0.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3740370,"resolution":"1","location":"assets","locale":"","width":1280,"height":960},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3740370,"resolution":"2","location":"assets","locale":"","width":1280,"height":960},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3740370,"resolution":"3","location":"assets","locale":"","width":1280,"height":960},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3740370,"resolution":"4","location":"assets","locale":"","width":1280,"height":960},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3740370,"resolution":"5","location":"assets","locale":"","width":1280,"height":960},"screenshot-6.png":{"filename":"screenshot-6.png","revision":3740370,"resolution":"6","location":"assets","locale":"","width":1280,"height":960}},"screenshots":{"1":"Letterkeep \u2192 Entries: every message is saved before any email is sent, and each entry shows whether your mail server accepted the notification \u2014 or the error it gave.","2":"Without JavaScript: after Send, the visitor sees what to fix above the form, the field is marked, and everything else they typed is still there.","3":"The form editor: each field is one box showing its label, type, required setting, width, name, placeholder and help text \u2014 no hidden panels. Drag a field, or use the arrows, to change the order.","4":"One entry: the visitor's answers, the form and page it came from, the mail status with its time, and Resend.","5":"Letterkeep \u2192 Settings: the From address is checked against your site's own domain, and Send test email shows what your mail server answered.","6":"The Import button on Letterkeep \u2192 Forms: each Contact Form 7 form, the fields that will be imported, and every tag that will not \u2014 each with its reason."}},"plugin_section":[],"plugin_tags":[358,2735,267,2253,19527],"plugin_category":[41],"plugin_contributors":[284373],"plugin_business_model":[],"class_list":["post-381944","plugin","type-plugin","status-publish","hentry","plugin_tags-contact-form","plugin_tags-contact-form-plugin","plugin_tags-email","plugin_tags-form-builder","plugin_tags-lead-form","plugin_category-communication","plugin_contributors-frostydev","plugin_committers-frostydev"],"banners":{"banner":"https:\/\/ps.w.org\/letterkeep-contact-form\/assets\/banner-772x250.png?rev=3740370","banner_2x":"https:\/\/ps.w.org\/letterkeep-contact-form\/assets\/banner-1544x500.png?rev=3740370","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/letterkeep-contact-form\/assets\/icon-128x128.png?rev=3740370","icon_2x":"https:\/\/ps.w.org\/letterkeep-contact-form\/assets\/icon-256x256.png?rev=3740370","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/letterkeep-contact-form\/assets\/screenshot-1.png?rev=3740370","caption":"Letterkeep \u2192 Entries: every message is saved before any email is sent, and each entry shows whether your mail server accepted the notification \u2014 or the error it gave."},{"src":"https:\/\/ps.w.org\/letterkeep-contact-form\/assets\/screenshot-2.png?rev=3740370","caption":"Without JavaScript: after Send, the visitor sees what to fix above the form, the field is marked, and everything else they typed is still there."},{"src":"https:\/\/ps.w.org\/letterkeep-contact-form\/assets\/screenshot-3.png?rev=3740370","caption":"The form editor: each field is one box showing its label, type, required setting, width, name, placeholder and help text \u2014 no hidden panels. Drag a field, or use the arrows, to change the order."},{"src":"https:\/\/ps.w.org\/letterkeep-contact-form\/assets\/screenshot-4.png?rev=3740370","caption":"One entry: the visitor's answers, the form and page it came from, the mail status with its time, and Resend."},{"src":"https:\/\/ps.w.org\/letterkeep-contact-form\/assets\/screenshot-5.png?rev=3740370","caption":"Letterkeep \u2192 Settings: the From address is checked against your site's own domain, and Send test email shows what your mail server answered."},{"src":"https:\/\/ps.w.org\/letterkeep-contact-form\/assets\/screenshot-6.png?rev=3740370","caption":"The Import button on Letterkeep \u2192 Forms: each Contact Form 7 form, the fields that will be imported, and every tag that will not \u2014 each with its reason."}],"raw_content":"<!--section=description-->\n<p>Most contact forms only email you. When the email fails \u2014 PHP mail switched off by the host, an SMTP password that expired, a notification filed as spam \u2014 the message is gone, and the visitor thinks you got it.<\/p>\n\n<p>Letterkeep Contact Form saves each entry in its own database table first. Then it emails you, and records what happened: every entry is marked <strong>Sent to your mail server<\/strong>, <strong>Failed<\/strong> with the error your server gave, or <strong>Not sent<\/strong>. A failed notification can be resent from the entry, and the settings screen can send a test email and tells you whether the From address is on your site's own domain.<\/p>\n\n<h4>Forms<\/h4>\n\n<ul>\n<li>Fields: text, email, phone, web address, number, date, paragraph, dropdown, choose one, checkboxes and a consent box \u2014 each with a label, required or not, placeholder, help text and full or half width.<\/li>\n<li>Four templates: Contact form, Quote request, Callback request and Newsletter signup.<\/li>\n<li>The block <em>Letterkeep Form<\/em> and the shortcode <code>[letterkeep id=\"\u2026\"]<\/code>.<\/li>\n<li>The form's stylesheet and script load only on pages that show a form, and need no jQuery.<\/li>\n<li>Works without JavaScript and behind page caching: the form posts to its own page, and a fresh security token is fetched when a visitor starts typing on a cached page.<\/li>\n<li>Accessible: every field has a label, required fields say so in words, and errors are linked to their fields with a summary at the top.<\/li>\n<li>After sending, the visitor sees your thank-you message, or goes to a page on your site that you choose.<\/li>\n<\/ul>\n\n<h4>Entries<\/h4>\n\n<ul>\n<li>Every entry is saved before any email is sent, with the page it was sent from.<\/li>\n<li>Letterkeep \u2192 Entries: search, a filter per form, unread and read, spam, delete, one entry at a time, and CSV export per form of exactly the entries the list shows.<\/li>\n<li>The CSV export puts an apostrophe in front of = + - or @ wherever a spreadsheet could start a formula, also when spaces or quotation marks stand before it: at the start of a value, and after a semicolon, tab or line break inside it, where a Danish, German or French Excel begins a new cell.<\/li>\n<li>If an entry cannot be saved, the email still goes out with the whole message and a line saying so; if neither works, the visitor is told the message was not sent.<\/li>\n<\/ul>\n\n<h4>Email<\/h4>\n\n<ul>\n<li>Send to one or more addresses, written plainly or as <code>Name &lt;address&gt;<\/code>. The subject and message can use <code>{field:name}<\/code>, <code>{all_fields}<\/code>, <code>{form_title}<\/code>, <code>{page_url}<\/code>, <code>{site_title}<\/code> and <code>{admin_email}<\/code>.<\/li>\n<li>From is wordpress@ your site's domain unless you choose another address, and the settings screen warns you when the address you chose is not on your site's domain. Reply-To is the visitor's email address in every new form that has an email field, so pressing Reply answers them.<\/li>\n<li>An optional automatic reply to the visitor, off by default.<\/li>\n<li><strong>Send test email<\/strong> shows your mail server's own answer, and a notice on Letterkeep's screens counts notifications that failed.<\/li>\n<\/ul>\n\n<h4>Spam, without a puzzle<\/h4>\n\n<ul>\n<li>Always on, without any account: a honeypot field, a check that the form was not sent within 3 seconds of loading, and at most 5 entries from one IP address per 10 minutes.<\/li>\n<li>Optional: Cloudflare Turnstile, hCaptcha or Google reCAPTCHA v3, with your own keys.<\/li>\n<li>If the CAPTCHA service does not answer, the entry is taken in and marked, instead of being turned away. If the service refuses your key, or its widget shows a visitor an error instead of its check (most often a key that does not list your domain), a notice tells you, and the entry is kept.<\/li>\n<li>While the CAPTCHA is passing your other visitors, a visitor who presses Send without answering a Turnstile or hCaptcha challenge in front of them is asked to confirm and press Send again, keeping what they typed \u2014 and a form that arrives without any answer the visitor could have given (JavaScript off, a blocked script, a widget that showed its own error, a reCAPTCHA v3 that never answered) is not turned away, but kept under Spam with that reason. When the CAPTCHA has passed no one for about a day, or since you changed its key or service, entries are taken in without the check, and a notice says it is not running on your forms.<\/li>\n<li>Everything caught as spam is kept under Spam for 30 days (at most 1,000 entries), with the reason \u2014 so a real message caught by mistake is not lost.<\/li>\n<\/ul>\n\n<h4>Switch from Contact Form 7<\/h4>\n\n<p>The Import button on Letterkeep \u2192 Forms reads your Contact Form 7 forms \u2014 Contact Form 7 does not need to be active. For each form it first shows what will come along and what will not, with a reason for every tag it leaves out. It imports the fields, the recipients, the subject and message, Mail (2) as the automatic reply, and your messages; if you say so, it also uses Contact Form 7's reCAPTCHA or Turnstile keys. It lists the pages where a Contact Form 7 shortcode or block is used, so you know which ones to update. Nothing in Contact Form 7 or on your pages is changed.<\/p>\n\n<p>Entries you collected with Flamingo or CFDB7 are not imported; they stay where they are.<\/p>\n\n<h4>Forms in and out<\/h4>\n\n<p>Export forms as a file and import them on the next site \u2014 fields, email settings and messages included.<\/p>\n\n<h4>Privacy<\/h4>\n\n<ul>\n<li>A consent box stores the text the visitor agreed to with the entry.<\/li>\n<li>Visitors' IP addresses are not saved unless you turn that on.<\/li>\n<li>Old entries can be deleted automatically after a number of days you choose.<\/li>\n<li>WordPress' own Export Personal Data and Erase Personal Data tools find entries by email address, and Letterkeep suggests text for your privacy policy.<\/li>\n<li>Deleting the plugin keeps your forms and entries, unless you tick \"Delete all Letterkeep data when the plugin is deleted\".<\/li>\n<\/ul>\n\n<h4>Letterkeep Pro<\/h4>\n\n<p>Letterkeep Pro is a paid add-on that sends each entry on to Mailchimp, Brevo, Kit, MailerLite, ActiveCampaign, HubSpot or a webhook, using API keys from your own accounts. When a connection stops accepting entries \u2014 a revoked key, an outage \u2014 Pro keeps them, emails you, and sends them again once it works. This plugin mentions it in five places: a Newsletter &amp; CRM tab under Letterkeep \u2192 Settings, a Send entries to your CRM button on the Entries screen once entries arrive, one line on new forms that you can hide, a link in the plugin's row on the Plugins screen, and \u2014 only when a Contact Form 7 form you import sent contacts to Brevo \u2014 one line in that form's import report. Everything in this plugin stays free.<\/p>\n\n<h3>External services<\/h3>\n\n<p>Letterkeep Contact Form sends nothing to its makers: no usage data, no licence check, no telemetry.<\/p>\n\n<p>It connects to a service only when the site owner turns on one of these CAPTCHA services under Letterkeep \u2192 Settings \u2192 Spam. Nothing is contacted while the setting is \"None\", which is the default.<\/p>\n\n<p><strong>Cloudflare Turnstile.<\/strong> On pages that show a form, the visitor's browser loads Turnstile's script from challenges.cloudflare.com, and Turnstile runs its check in the browser. When the form is sent, the site's server posts the resulting token, the site's secret key and the visitor's IP address to https:\/\/challenges.cloudflare.com\/turnstile\/v0\/siteverify to learn whether the check passed. Terms: https:\/\/www.cloudflare.com\/website-terms\/ \u2014 Privacy: https:\/\/www.cloudflare.com\/turnstile-privacy-policy\/<\/p>\n\n<p><strong>hCaptcha.<\/strong> On pages that show a form, the visitor's browser loads hCaptcha's script from js.hcaptcha.com. When the form is sent, the site's server posts the token, the secret key and the visitor's IP address to https:\/\/api.hcaptcha.com\/siteverify. Terms: https:\/\/www.hcaptcha.com\/terms \u2014 Privacy: https:\/\/www.hcaptcha.com\/privacy<\/p>\n\n<p><strong>Google reCAPTCHA v3.<\/strong> On pages that show a form, the visitor's browser loads reCAPTCHA's script from www.google.com. When the form is sent, the site's server posts the token, the secret key and the visitor's IP address to https:\/\/www.google.com\/recaptcha\/api\/siteverify, which answers with a score. Terms: https:\/\/policies.google.com\/terms \u2014 Privacy: https:\/\/policies.google.com\/privacy<\/p>\n\n<p>Like every request WordPress makes, these carry the site's address and WordPress version in the User-Agent header. Each check has a 5-second time limit; if the service does not answer, the entry is saved anyway and marked as not checked.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>In your WordPress admin, go to Plugins \u2192 Add New Plugin, search for \"Letterkeep Contact Form\", then install and activate it.<\/li>\n<li>Activation creates one form, <em>Contact form<\/em>, with the fields Name, Email and Message. It is sent to your site's admin address.<\/li>\n<li>Open Letterkeep \u2192 Forms. Each form shows its shortcode and the name of its block: add the block <em>Letterkeep Form<\/em> to a page, or paste the shortcode.<\/li>\n<li>Open Letterkeep \u2192 Settings and press <strong>Send test email<\/strong> to see what your mail server answers.<\/li>\n<li>Coming from Contact Form 7? Press Import on Letterkeep \u2192 Forms.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"where%20do%20the%20entries%20go%3F\"><h3>Where do the entries go?<\/h3><\/dt>\n<dd><p>Into two tables of Letterkeep's own in your WordPress database \u2014 one for forms, one for entries \u2014 before any email is sent. You find them under Letterkeep \u2192 Entries.<\/p><\/dd>\n<dt id=\"will%20my%20emails%20arrive%20now%3F\"><h3>Will my emails arrive now?<\/h3><\/dt>\n<dd><p>Letterkeep sends through WordPress' own <code>wp_mail()<\/code>, as Contact Form 7, WPForms and Fluent Forms do. What it changes is that you can see what happened: each entry shows whether your mail server accepted the notification and, if not, the exact error. The entry is saved either way.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20smtp%20plugins%3F\"><h3>Does it work with SMTP plugins?<\/h3><\/dt>\n<dd><p>Yes. It sends through <code>wp_mail()<\/code>, which SMTP plugins such as WP Mail SMTP and FluentSMTP take over, and it records the outcome WordPress reports back.<\/p><\/dd>\n<dt id=\"does%20it%20work%20without%20javascript%2C%20and%20with%20page%20caching%3F\"><h3>Does it work without JavaScript, and with page caching?<\/h3><\/dt>\n<dd><p>Yes. Without JavaScript the form posts to its own page; after a successful send, the page is loaded again with the thank-you message, so refreshing it does not send the form twice. On a cached page, a fresh security token is fetched when a visitor starts typing. A CAPTCHA, if you turn one on, needs JavaScript in the visitor's browser; without it, the visitor is told the check cannot run, and the message is kept under Spam while the CAPTCHA is working for your other visitors.<\/p><\/dd>\n<dt id=\"do%20i%20need%20a%20captcha%3F\"><h3>Do I need a CAPTCHA?<\/h3><\/dt>\n<dd><p>Usually not. The honeypot, the 3-second check and the limit per IP address are always on. If spam still gets through, turn on Cloudflare Turnstile, hCaptcha or reCAPTCHA v3 under Letterkeep \u2192 Settings \u2192 Spam, with keys from your own account.<\/p><\/dd>\n<dt id=\"what%20happens%20to%20a%20message%20that%20is%20caught%20as%20spam%3F\"><h3>What happens to a message that is caught as spam?<\/h3><\/dt>\n<dd><p>It is saved under Spam with the reason, no notification is sent, and the visitor sees the normal thank-you message. It is kept for 30 days, at most 1,000 entries.<\/p><\/dd>\n<dt id=\"can%20it%20take%20file%20uploads%2C%20check%20spam%20with%20akismet%2C%20or%20show%20fields%20depending%20on%20other%20answers%3F\"><h3>Can it take file uploads, check spam with Akismet, or show fields depending on other answers?<\/h3><\/dt>\n<dd><p>Not in this version. File uploads, Akismet and conditional logic are on the list for later versions, without a date. Until then, the honeypot, the 3-second check, the IP limit and an optional CAPTCHA handle spam.<\/p><\/dd>\n<dt id=\"does%20it%20load%20anything%20on%20pages%20without%20a%20form%3F\"><h3>Does it load anything on pages without a form?<\/h3><\/dt>\n<dd><p>No. The stylesheet, the script and any CAPTCHA script are only added to a page that shows a Letterkeep form.<\/p><\/dd>\n<dt id=\"what%20happens%20when%20i%20delete%20the%20plugin%3F\"><h3>What happens when I delete the plugin?<\/h3><\/dt>\n<dd><p>Your forms and entries stay, so a reinstall finds them again \u2014 unless you tick \"Delete all Letterkeep data when the plugin is deleted\" under Letterkeep \u2192 Settings \u2192 Privacy first.<\/p><\/dd>\n<dt id=\"is%20there%20a%20paid%20version%3F\"><h3>Is there a paid version?<\/h3><\/dt>\n<dd><p>Yes, Letterkeep Pro, an add-on that sends entries on to newsletter and CRM services and tells you when one of them refuses entries or stops answering. It is described above under Letterkeep Pro. Nothing in this plugin is locked, limited or switched off without it.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>First release.<\/li>\n<\/ul>","raw_excerpt":"A contact form that saves every entry in WordPress before it sends anything, and shows whether each email reached your mail server.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/en-ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/381944","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/en-ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/en-ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/en-ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=381944"}],"author":[{"embeddable":true,"href":"https:\/\/en-ca.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/frostydev"}],"wp:attachment":[{"href":"https:\/\/en-ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=381944"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/en-ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=381944"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/en-ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=381944"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/en-ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=381944"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/en-ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=381944"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/en-ca.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=381944"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}