{"id":326541,"date":"2026-07-05T07:54:10","date_gmt":"2026-07-05T07:54:10","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/emerge-campaigns\/"},"modified":"2026-07-05T07:53:54","modified_gmt":"2026-07-05T07:53:54","slug":"emerge-campaigns","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/emerge-campaigns\/","author":18311397,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.0","stable_tag":"1.0.0","tested":"7.0","requires":"6.0","requires_php":"8.1","requires_plugins":null,"header_name":"Emerge Campaigns","header_author":"Redigit","header_description":"Self-hosted email campaigns for WordPress. Authored in the block editor, sent through wp_mail(), tracked in your own database.","assets_banners_color":"222a3b","last_updated":"2026-07-05 07:53:54","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/emerge.redigit.net\/wp-campaigns","header_author_uri":"https:\/\/redigit.net\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":29,"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":"redigit","date":"2026-07-05 07:53:54"}},"upgrade_notice":{"1.0.0":"<p>First public release on the WordPress plugin repository.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3596495,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3596495,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3596495,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3596495,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":{"emerge-campaigns\/subscribe":{"$schema":"https:\/\/schemas.wp.org\/trunk\/block.json","apiVersion":3,"name":"emerge-campaigns\/subscribe","version":"1.0.0","title":"Emerge Subscribe","category":"widgets","icon":"email","description":"Email subscription form. Submissions are added to Emerge Campaigns as contacts.","keywords":["subscribe","newsletter","email","form"],"textdomain":"emerge-campaigns","supports":{"html":false,"anchor":true,"align":["wide","full"]},"attributes":{"heading":{"type":"string","default":"Subscribe to our newsletter"},"description":{"type":"string","default":"Get our latest posts in your inbox."},"button":{"type":"string","default":"Subscribe"},"showName":{"type":"boolean","default":false},"consent":{"type":"string","default":""}},"editorScript":"file:.\/index.js"}},"tagged_versions":["1.0.0"],"block_files":[],"assets_screenshots":[],"screenshots":{"1":"Contacts list table with status\/source filters and a per-row edit screen showing segments and send history.","2":"Segment edit screen \u2014 static contact picker and dynamic rule builder.","3":"Template edit screen \u2014 block editor with Subject and Preheader meta box plus Send-test and Preview controls.","4":"Broadcasts list table (one-time sends) with progress column and row actions.","5":"Newsletters list table (recurring series) with cadence, plus the read-only Issues log for a series.","6":"Campaign edit screen \u2014 main form, cadence + send-time controls, test-send block, performance stats, and recent failures with retry.","7":"Settings screen with contact source toggles, per-minute send cap, dead-end auto-pause threshold, and bounce handling.","8":"Emerge Subscribe form rendered on the front end via shortcode, block, or widget."}},"plugin_section":[],"plugin_tags":[20199,264,455,23267,2482],"plugin_category":[41,42],"plugin_contributors":[265055],"plugin_business_model":[],"class_list":["post-326541","plugin","type-plugin","status-publish","hentry","plugin_tags-email-campaigns","plugin_tags-email-marketing","plugin_tags-newsletter","plugin_tags-segments","plugin_tags-subscribe","plugin_category-communication","plugin_category-contact-forms","plugin_contributors-redigit","plugin_committers-redigit"],"banners":{"banner":"https:\/\/ps.w.org\/emerge-campaigns\/assets\/banner-772x250.png?rev=3596495","banner_2x":"https:\/\/ps.w.org\/emerge-campaigns\/assets\/banner-1544x500.png?rev=3596495","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/emerge-campaigns\/assets\/icon-128x128.png?rev=3596495","icon_2x":"https:\/\/ps.w.org\/emerge-campaigns\/assets\/icon-256x256.png?rev=3596495","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>Emerge Campaigns turns WordPress into a self-hosted email-marketing tool. Build contact lists from your existing WordPress audience, group them into static or dynamic segments, author HTML emails in the block editor, schedule one-off or recurring campaigns, and track opens, clicks, and unsubscribes \u2014 all without leaving wp-admin.<\/p>\n\n<p>Sends dispatch through WordPress's standard <code>wp_mail()<\/code> function, so the plugin works with whatever mail transport your site is already configured for \u2014 host SMTP, a transactional service plugin, or PHP's default mail.<\/p>\n\n<h4>Key features<\/h4>\n\n<ul>\n<li><strong>Contacts from your existing WordPress audience<\/strong> \u2014 daily background sync pulls in WordPress users, comment authors, WooCommerce customers, Easy Digital Downloads customers, Jetpack contact form submissions, Jetpack Subscriptions, MailPoet subscribers, Newsletter Plugin subscribers, Contact Form 7 (via Flamingo) submissions, and Gravity Forms entries. Each source is opt-in from the settings screen. Manual add is supported from the Contacts screen.<\/li>\n<li><strong>Static and dynamic segments<\/strong> \u2014 static segments are manually-curated lists. Dynamic segments are rule-based (status, source, subscribed-at) and re-evaluated at send time, so membership stays current as new contacts arrive.<\/li>\n<li><strong>Block-editor email templates<\/strong> \u2014 author emails using Gutenberg, including Query Loop blocks to pull recent posts into newsletters. Mustache-style merge tags (<code>{{first_name}}<\/code>, <code>{{email}}<\/code>, <code>{{site_name}}<\/code>, <code>{{unsubscribe_url}}<\/code>, <code>{{view_in_browser_url}}<\/code>) substituted at send time. Starter newsletter and receipt block patterns included in a dedicated email category.<\/li>\n<li><strong>Broadcasts and Newsletters<\/strong> \u2014 two dedicated surfaces over the same engine. <em>Broadcasts<\/em> are one-time sends: draft \u2192 scheduled \u2192 sending \u2192 sent \/ paused \/ cancelled, with schedule-for-later, pause\/resume in-flight, and duplicate-as-draft. <em>Newsletters<\/em> are recurring series: pick a daily \/ weekly \/ monthly cadence and a send time, and a background sweeper spawns each issue automatically, picking up template and segment changes on the parent.<\/li>\n<li><strong>Newsletter issue log &amp; smart resend<\/strong> \u2014 every newsletter keeps a read-only Issues log (the original send plus each recurring issue, numbered to match the subject line), with pause\/stop controls for an issue that's mid-send. An opt-in \"send only if content changed\" gate re-renders the template each run and skips the send when nothing meaningful changed \u2014 nonces, per-render ids, and insignificant whitespace are normalized out so only genuine content changes trigger a new issue.<\/li>\n<li><strong>Background batched sending<\/strong> \u2014 Action Scheduler chained batches with a configurable per-minute throttle (default 2\/min \u2248 120\/hour) to stay within mail-provider rate limits. Action Scheduler is bundled \u2014 no separate install required.<\/li>\n<li><strong>Resilient failure handling<\/strong> \u2014 syntactically invalid email addresses are skipped per-recipient rather than failing the whole campaign. When the underlying mail transport breaks (N consecutive <code>wp_mail()<\/code> failures, configurable in Settings \u2192 Sending), the campaign auto-pauses and resets failed sends back to pending so they aren't lost.<\/li>\n<li><strong>Retry failed sends<\/strong> \u2014 one-click button on the campaign edit screen re-queues transport failures once delivery is healthy again. Legitimate skips (unsubscribed, missing contact, invalid address) are not re-queued.<\/li>\n<li><strong>Emerge Subscribe \u2014 public-facing signup form<\/strong> \u2014 accept new subscribers in three interchangeable ways: a <code>[emerge_campaigns_subscribe]<\/code> shortcode, an \"Emerge Subscribe\" block in the block editor, or an \"Emerge Subscribe\" classic widget. Same configuration shape across all three (heading, description, button label, optional first\/last name fields, optional consent text). Submissions are tagged with the <code>emerge_subscribe<\/code> source and recorded with explicit consent so they're identifiable in segment rules.<\/li>\n<li><strong>Progressive-enhancement AJAX submit<\/strong> \u2014 the subscribe form posts to a REST endpoint via vanilla JavaScript and renders the result inline with no page reload. Falls back cleanly to a classic POST + redirect path when JavaScript is disabled or fails to load. Same nonce, same validation, only the transport differs.<\/li>\n<li><strong>Spam controls on the subscribe form<\/strong> \u2014 nonce verification, hidden honeypot field, and a per-IP rate limit (default 5\/hour, filterable).<\/li>\n<li><strong>Test sends and preview<\/strong> \u2014 send a test to any address from the campaign edit screen with full merge-tag substitution. Preview templates in the browser before assigning them to a campaign.<\/li>\n<li><strong>Per-recipient tokens<\/strong> \u2014 every send gets a unique token used for unsubscribe, view-in-browser, open-pixel, and click-tracking URLs. No shared secrets, no guessable URLs.<\/li>\n<li><strong>RFC 8058 one-click unsubscribe<\/strong> \u2014 <code>List-Unsubscribe-Post<\/code> headers so Gmail and Apple Mail show a native unsubscribe button.<\/li>\n<li><strong>Built-in analytics<\/strong> \u2014 open pixel, click redirect, and unsubscribe events recorded locally in your own database. Per-campaign stats (sent, opens, unique opens, clicks, unique clicks, unsubscribes, rates) and per-contact send history visible inside wp-admin.<\/li>\n<li><strong>Privacy-conscious tracking<\/strong> \u2014 IP addresses are stored as a salted SHA-256 hash, never in the clear. Open pixel is opt-out via the wrapper filter.<\/li>\n<li><strong>Bounce &amp; complaint handling<\/strong> \u2014 when the companion Emerge Mail plugin is active, Emerge Campaigns consumes its <code>emerge_mail_bounce_received<\/code> events and reflects them onto contacts: hard bounces and complaints are suppressed (dropped from the mailable audience and hidden from the default Contacts view), soft bounces are marked but kept mailable. Optional, guarded cleanup on a hard bounce can delete a linked WordPress user (reassigning their content) and reassign the address's anonymous comments to a fallback user.<\/li>\n<li><strong>Authenticated subscribe webhook<\/strong> \u2014 besides the public form, an API-key-protected REST endpoint (<code>POST \/wp-json\/emerge-campaigns\/v1\/webhook\/subscribe<\/code>, <code>x-api-key<\/code> header) lets external systems add contacts programmatically. Generate or revoke the key from Settings; webhook signups are tagged with the <code>webhook<\/code> source.<\/li>\n<\/ul>\n\n<h4>How it works<\/h4>\n\n<p>When you activate the plugin, it creates its own custom database tables for contacts, segments, campaigns, sends, and events. A daily background job populates your contacts from whichever sources you've enabled under Settings.<\/p>\n\n<p>You author email templates in the block editor. When you build a campaign, you pick a template and a segment; on send, the segment is snapshotted into per-recipient send records (one per recipient, idempotent so re-runs never duplicate). A background worker picks up batches of pending sends, renders the template with each recipient's merge context, dispatches via <code>wp_mail()<\/code>, and records the result.<\/p>\n\n<p>Recurring campaigns are driven by a small sweep job: at each interval (daily \/ weekly \/ monthly), the sweeper duplicates the parent campaign as a fresh child and queues it for send. The parent stays editable, so changes to the template or segment propagate to the next occurrence.<\/p>\n\n<p>Public signups via the subscribe shortcode \/ block \/ widget are inserted directly into the contacts table with explicit consent and the source <code>emerge_subscribe<\/code>, so they show up in the Contacts list table and can be targeted by segment rules.<\/p>\n\n<p>Tracking is opt-out via the wrapper filter. By default, every email includes a 1\u00d71 pixel that hits <code>?emerge_open=&lt;token&gt;<\/code> when loaded, and rewritten link targets that hit <code>?emerge_click=&lt;token&gt;&amp;url=&lt;encoded&gt;<\/code> before redirecting to the real destination.<\/p>\n\n<h4>What this is not<\/h4>\n\n<ul>\n<li>Not a SaaS \u2014 nothing is hosted off your site. All data, including tracking events, lives in your database.<\/li>\n<li>Not an SMTP plugin \u2014 Emerge Campaigns hands sends to WordPress's <code>wp_mail()<\/code> and lets your existing mail configuration take it from there.<\/li>\n<li>Not a transactional-only tool \u2014 <code>wp_mail()<\/code> calls from other plugins (password resets, order receipts) are not intercepted. This plugin is for outbound campaigns you compose and send yourself.<\/li>\n<\/ul>\n\n<h3>External services<\/h3>\n\n<p>Emerge Campaigns does not contact any external service. All sending, tracking, and storage stays on your WordPress site.<\/p>\n\n<p>Sends are dispatched via WordPress's <code>wp_mail()<\/code> function. Whatever delivery mechanism your site is configured for \u2014 PHP's default mail, host SMTP, or another plugin that hooks <code>wp_mail<\/code> \u2014 handles the actual transport. Emerge Campaigns does not call any third-party API directly.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>emerge-campaigns<\/code> folder to <code>\/wp-content\/plugins\/<\/code>, or install via the Plugins screen.<\/li>\n<li>Activate the plugin from the Plugins menu.<\/li>\n<li>Action Scheduler is bundled \u2014 no separate install is needed for reliable background sending.<\/li>\n<li>Visit <strong>Emerge Campaigns \u2192 Settings<\/strong> and pick which contact sources to sync from. Then visit <strong>Emerge Campaigns \u2192 Contacts<\/strong> \u2014 the first sync runs an hour after activation; click <strong>Sync now<\/strong> to populate immediately.<\/li>\n<li>Author your first template under <strong>Emerge Campaigns \u2192 Templates<\/strong> and build a campaign under <strong>Emerge Campaigns \u2192 Campaigns<\/strong>.<\/li>\n<li>To accept public signups, drop the <code>[emerge_campaigns_subscribe]<\/code> shortcode on a page, add the \"Emerge Subscribe\" block in the editor, or add the \"Emerge Subscribe\" widget to a sidebar.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"how%20do%20sends%20actually%20get%20delivered%3F\"><h3>How do sends actually get delivered?<\/h3><\/dt>\n<dd><p>Emerge Campaigns dispatches every send via WordPress's <code>wp_mail()<\/code> function \u2014 the same function any other WordPress plugin uses to send email. Whatever transport your site is already configured for (host SMTP, a transactional-email plugin, or PHP's default mail) handles the actual delivery. Deliverability depends on that configuration.<\/p><\/dd>\n<dt id=\"where%20do%20contacts%20come%20from%3F\"><h3>Where do contacts come from?<\/h3><\/dt>\n<dd><p>A daily background sync pulls from whichever sources you enable in Settings: WordPress users, comment authors, WooCommerce customers, Easy Digital Downloads customers, Jetpack contact form submissions, Jetpack Subscriptions, MailPoet subscribers, Newsletter Plugin subscribers, Contact Form 7 submissions (via Flamingo), and Gravity Forms entries. You can also add contacts manually from the Contacts screen, and accept self-signups via the Emerge Subscribe form (shortcode, block, or widget).<\/p><\/dd>\n<dt id=\"what%27s%20the%20difference%20between%20static%20and%20dynamic%20segments%3F\"><h3>What's the difference between static and dynamic segments?<\/h3><\/dt>\n<dd><p>A <strong>static segment<\/strong> is a manually-curated list \u2014 pick the contacts you want, save the segment, those contacts are members until you remove them. A <strong>dynamic segment<\/strong> is a rule definition (e.g. \"source = woocommerce AND subscribed_at &gt;= 2026-01-01\") evaluated at send time, so membership stays current as new contacts arrive.<\/p><\/dd>\n<dt id=\"what%27s%20the%20difference%20between%20a%20broadcast%20and%20a%20newsletter%3F\"><h3>What's the difference between a Broadcast and a Newsletter?<\/h3><\/dt>\n<dd><p>A <strong>Broadcast<\/strong> is a one-time send \u2014 compose it, pick an audience, and send now or schedule it for later. A <strong>Newsletter<\/strong> is a recurring series: you choose a daily \/ weekly \/ monthly cadence and a time of day, and a background sweep spawns each issue automatically. Newsletters have their own menu and a read-only Issues log showing every issue that's gone out. Both are built on the same engine; they're just separated so the one-off and ongoing workflows stay uncluttered.<\/p><\/dd>\n<dt id=\"can%20i%20send%20recurring%20newsletters%3F\"><h3>Can I send recurring newsletters?<\/h3><\/dt>\n<dd><p>Yes \u2014 that's what the Newsletter surface is for. Set a daily, weekly, or monthly cadence with a send time; a background sweep job spawns the next issue as a fresh child campaign at each interval. The parent stays editable, so changes to the template or segment propagate forward. By default a new issue is only spawned when the rendered content has actually changed since the last one (an opt-out \"send only if content changed\" checkbox) \u2014 ideal for newsletters that pull dynamic content like recent posts. You can pause or stop the series at any time.<\/p><\/dd>\n<dt id=\"what%20happens%20when%20an%20address%20bounces%20or%20reports%20spam%3F\"><h3>What happens when an address bounces or reports spam?<\/h3><\/dt>\n<dd><p>If the companion Emerge Mail plugin is delivering your mail, it reports bounces and complaints back to Emerge Campaigns. A hard bounce or spam complaint suppresses the contact \u2014 it's dropped from the mailable audience and hidden from the default Contacts view \u2014 while a soft bounce is marked but kept mailable. On a hard bounce you can optionally (off by default) delete a linked WordPress user, reassigning their content, and reassign the bounced address's anonymous comments to a fallback user. Without Emerge Mail, this is simply inactive.<\/p><\/dd>\n<dt id=\"can%20i%20use%20query%20loop%20blocks%20in%20email%20templates%3F\"><h3>Can I use Query Loop blocks in email templates?<\/h3><\/dt>\n<dd><p>Yes. Templates render through the same <code>the_content<\/code> filter pipeline as front-end posts, so Query Loop and any other block that works in posts works in emails. This is especially useful for newsletter templates that pull in recent posts dynamically.<\/p><\/dd>\n<dt id=\"how%20do%20i%20add%20a%20subscribe%20form%20to%20my%20site%3F\"><h3>How do I add a subscribe form to my site?<\/h3><\/dt>\n<dd><p>Three ways, all interchangeable: drop the <code>[emerge_campaigns_subscribe]<\/code> shortcode anywhere on a post or page; add the \"Emerge Subscribe\" block in the block editor; or add the \"Emerge Subscribe\" widget to a sidebar or block-based widget area. All three render the same form, accept the same options (heading, description, button label, optional first\/last name fields, optional consent line), and submit to the same endpoint. Submissions land in the Contacts table with source <code>emerge_subscribe<\/code>.<\/p><\/dd>\n<dt id=\"does%20the%20subscribe%20form%20work%20without%20javascript%3F\"><h3>Does the subscribe form work without JavaScript?<\/h3><\/dt>\n<dd><p>Yes. With JavaScript enabled, submissions go through a small vanilla-JS module that posts to a REST endpoint and renders the result inline with no page reload. With JavaScript disabled or blocked, the same form falls back to a classic POST + redirect that surfaces the same result inline on the next render. Same nonce, same validation, only the transport differs.<\/p><\/dd>\n<dt id=\"how%20does%20unsubscribe%20work%3F\"><h3>How does unsubscribe work?<\/h3><\/dt>\n<dd><p>Every send has a unique token. The token is used to build a per-recipient unsubscribe URL placed in both the email body (<code>{{unsubscribe_url}}<\/code>) and the <code>List-Unsubscribe<\/code> header. Mail clients that support RFC 8058 (Gmail, Apple Mail) show a native one-click unsubscribe button that POSTs to the URL without a browser round-trip.<\/p><\/dd>\n<dt id=\"how%20are%20opens%20and%20clicks%20tracked%3F\"><h3>How are opens and clicks tracked?<\/h3><\/dt>\n<dd><p>Opens are tracked via an invisible 1\u00d71 pixel placed at the bottom of every email. Clicks are tracked by rewriting <code>&lt;a href&gt;<\/code> targets to a redirect URL on your site, which records the click and 302-redirects to the real destination. Tracking can be disabled site-wide by replacing the wrapper template via the <code>emerge_campaigns_email_wrapper<\/code> filter.<\/p><\/dd>\n<dt id=\"how%20is%20recipient%20privacy%20protected%3F\"><h3>How is recipient privacy protected?<\/h3><\/dt>\n<dd><p>IP addresses are never stored in the clear. When a recipient opens an email or clicks a link, their IP is salted (with <code>wp_salt('auth')<\/code>) and SHA-256 hashed before it's recorded with the event. The hash is stable per-site (so we can count unique recipients) but the raw IP can't be recovered. User agents are stored verbatim for delivery diagnostics, capped at 255 characters.<\/p><\/dd>\n<dt id=\"what%20happens%20if%20a%20send%20fails%3F\"><h3>What happens if a send fails?<\/h3><\/dt>\n<dd><p>The send row is marked <code>failed<\/code> with the error stored alongside it. Failed sends show on the campaign edit screen with recipient email and error reason \u2014 up to the 50 most recent. The campaign keeps sending; one failure doesn't pause the whole batch.<\/p>\n\n<p>Syntactically invalid email addresses and per-recipient bounces are recorded as terminal failures (<code>invalid_email<\/code>, <code>recipient_bounced<\/code>) and skipped \u2014 they don't pause the campaign. But if N consecutive <code>wp_mail()<\/code> calls return false from the same transport (default 10, configurable in Settings \u2192 Sending, set to 0 to disable), the campaign auto-pauses and the burst of failures is reset to pending so nothing is lost. A <strong>Retry failed sends<\/strong> button on the campaign edit screen lets you re-queue them once delivery is healthy.<\/p><\/dd>\n<dt id=\"can%20i%20throttle%20sends%20to%20stay%20within%20mail-provider%20rate%20limits%3F\"><h3>Can I throttle sends to stay within mail-provider rate limits?<\/h3><\/dt>\n<dd><p>Yes. Set <strong>Maximum sends per minute<\/strong> on <strong>Emerge Campaigns \u2192 Settings<\/strong>. The send worker clamps each batch to the remaining budget and defers to the start of the next minute when exhausted. Default is 2 (\u2248 120\/hour); set to 0 for unlimited. Smaller per-minute batches keep each Action Scheduler dispatch short and resilient to provider latency spikes.<\/p><\/dd>\n<dt id=\"is%20%60wp_mail%60%20modified%20or%20replaced%20by%20this%20plugin%3F\"><h3>Is `wp_mail` modified or replaced by this plugin?<\/h3><\/dt>\n<dd><p>No. Campaigns are dispatched via <code>wp_mail()<\/code> like any other plugin's email, so transactional <code>wp_mail()<\/code> calls from elsewhere in WordPress are unaffected.<\/p><\/dd>\n<dt id=\"how%20do%20i%20remove%20all%20data%20on%20uninstall%3F\"><h3>How do I remove all data on uninstall?<\/h3><\/dt>\n<dd><p>Deleting the plugin from the Plugins screen runs <code>uninstall.php<\/code>, which drops all six custom tables, deletes plugin options, and clears all scheduled jobs.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.0<\/h4>\n\n<p>First public release.<\/p>\n\n<ul>\n<li>Contacts table with daily background sync from WordPress users, comment authors, WooCommerce customers, Easy Digital Downloads customers, Jetpack contact form submissions, Jetpack Subscriptions, MailPoet subscribers, Newsletter Plugin subscribers, Contact Form 7 (Flamingo) submissions, and Gravity Forms entries. Each source toggleable from settings; manual add supported.<\/li>\n<li>Static segments (manual contact picker) and dynamic segments (rule builder over status \/ source \/ subscribed_at), re-evaluated at send time.<\/li>\n<li>Email templates authored as custom posts in the block editor, with merge tags, starter block patterns (newsletter + receipt), test-send, and preview.<\/li>\n<li>Broadcasts \u2014 one-time sends with the full draft \/ scheduled \/ sending \/ sent \/ paused \/ cancelled lifecycle, schedule-for-later, pause\/resume in-flight, and duplicate-as-draft.<\/li>\n<li>Newsletters \u2014 recurring series on a daily \/ weekly \/ monthly cadence with a send time, spawned automatically by a background sweep. Read-only per-series Issues log with pause\/stop controls for an in-flight issue, and an opt-in \"send only if content changed\" gate that uses normalized-render hashing so nonces, per-render ids, and whitespace never trigger spurious issues.<\/li>\n<li>Background batched send worker via bundled Action Scheduler, with a settings-configured per-minute throttle (default 2\/min \u2248 120\/hour).<\/li>\n<li>Per-recipient skip codes (<code>invalid_email<\/code>, <code>recipient_bounced<\/code>) so per-contact data problems don't pause healthy campaigns.<\/li>\n<li>Dead-end auto-pause: when N consecutive transport failures occur (default 10, configurable), the campaign auto-pauses and the burst of failures resets back to pending. One-click \"Retry failed sends\" re-queues transport failures once delivery is healthy.<\/li>\n<li>Bounce &amp; complaint handling: consumes the companion Emerge Mail plugin's <code>emerge_mail_bounce_received<\/code> events \u2014 hard bounces and complaints suppress the contact, soft bounces are marked but kept mailable \u2014 with optional, guarded hard-bounce cleanup (delete a linked WordPress user with content reassignment; reassign the address's anonymous comments to a fallback user).<\/li>\n<li>Per-recipient send tokens for unsubscribe, view-in-browser, open-pixel, and click-tracking URLs. RFC 8058 <code>List-Unsubscribe<\/code> \/ <code>List-Unsubscribe-Post<\/code> headers for native one-click unsubscribe in Gmail and Apple Mail.<\/li>\n<li>Open-pixel + click-redirect tracking recorded in your own database; IPs stored only as salted SHA-256 hashes. Per-campaign stats (sent, opens, unique opens, clicks, unique clicks, unsubscribes, rates) and per-contact send history on the admin screens.<\/li>\n<li>Emerge Subscribe: public signup form available three ways \u2014 <code>[emerge_campaigns_subscribe]<\/code> shortcode, \"Emerge Subscribe\" block, and classic widget \u2014 all sharing identical output and configuration, with progressive-enhancement AJAX submit and a no-JS POST + redirect fallback. Spam controls: nonce verification, hidden honeypot, and a per-IP rate limit (default 5\/hour, filterable).<\/li>\n<li>Authenticated subscribe webhook: API-key-protected REST endpoint (<code>POST \/wp-json\/emerge-campaigns\/v1\/webhook\/subscribe<\/code>, <code>x-api-key<\/code> header) for adding contacts programmatically; webhook signups tagged with the <code>webhook<\/code> source.<\/li>\n<li>Extension points for integrators: <code>emerge_campaigns_subscribed<\/code>, <code>emerge_campaigns_bounce_recorded<\/code>, <code>emerge_campaigns_dead_end_paused<\/code>, and <code>emerge_campaigns_email_wrapper<\/code>.<\/li>\n<\/ul>","raw_excerpt":"Self-hosted email campaigns for WordPress. Authored in the block editor, sent through your own mailbox, tracked in your own database.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/326541","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=326541"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/redigit"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=326541"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=326541"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=326541"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=326541"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=326541"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=326541"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}