CampaignCanvas 1.2.6
dotnet add package CampaignCanvas --version 1.2.6
NuGet\Install-Package CampaignCanvas -Version 1.2.6
<PackageReference Include="CampaignCanvas" Version="1.2.6" />
<PackageVersion Include="CampaignCanvas" Version="1.2.6" />
<PackageReference Include="CampaignCanvas" />
paket add CampaignCanvas --version 1.2.6
#r "nuget: CampaignCanvas, 1.2.6"
#:package CampaignCanvas@1.2.6
#addin nuget:?package=CampaignCanvas&version=1.2.6
#tool nuget:?package=CampaignCanvas&version=1.2.6
CampaignCanvas
Forms and email marketing for Umbraco — without leaving the backoffice.
CampaignCanvas takes the whole journey from capturing a visitor to sending the campaign and brings it inside Umbraco 17. Build forms, manage submissions, grow mailing lists, design on-brand emails with the native Block Grid editor, and send campaigns, automated digests, and transactional email — one package, one licence, one audit trail. No third-party marketing suite to wire up, no copy-pasting contacts between systems.
It's built natively for the new Umbraco backoffice (Bellissima), so it looks and feels like part of the CMS your editors already know — not a bolted-on iframe.
Why teams choose CampaignCanvas
- Forms and newsletters, finally together. They share a section, a licence, and an audit log — so a contact form can opt a visitor straight into a mailing list with zero glue code.
- No per-contact SaaS fees. Your subscribers and submissions live in your own database. Send through the email provider you already trust — SendGrid, Postmark, Mailgun, Resend, or plain SMTP.
- GDPR-ready from day one. Double opt-in, one-click unsubscribe, consent history, suppression lists, subject-access search, and right-to-erasure are built in — not add-ons.
- Loved by editors, respected by developers. Drag-and-drop form and email building in the backoffice, backed by a headless API, view components, and pluggable interfaces for the team behind the site.
- Ready to scale. Engineered for 50,000+ subscribers from the first install, with indexed tables behind every field you'll filter or segment on.
A complete form builder
- 15 field types — text, email, number, date, dropdowns, star ratings, file uploads, consent checkboxes, and more
- Multi-step wizard forms with progress indicators
- Conditional fields that appear and hide based on earlier answers — re-checked on the server, so client-side tricks can't slip past validation
- A submissions inbox with file downloads, status tracking, charts, and CSV export
- Spam protection that works quietly: honeypot, time-to-submit heuristics, Google reCAPTCHA v3, and Cloudflare Turnstile
- An action on every submission — email notifications, autoresponders, webhooks, Slack, Microsoft Teams, and Discord
- Drop any form onto a page with a single view component, or let editors pick one with the Form Picker property editor
Email campaigns, designed inside Umbraco
- Compose emails with Umbraco's native Block Grid editor, constrained to an email-safe block set that renders everywhere
- Reusable brand themes — colours, fonts, buttons, spacing — so every send is on-brand without touching HTML
- Personalisation with merge fields for any subscriber detail, including your own custom fields
- Live preview in desktop, mobile, dark-mode, and plain-text — plus one-click test sends before you commit
- Mailing lists, tags, custom fields, and saved segments with live recipient counts as you build them
- Schedule sends, require sign-off before anything goes out, and collaborate with per-campaign comments and clear roles (drafter / reviewer / sender)
Newsletters that send themselves
Point a digest campaign at any Umbraco content type, choose a schedule and a minimum number of items, and CampaignCanvas builds and sends the newsletter for you — daily, weekly, or monthly. Ideal for "latest articles" or "new listings" roundups, with an optional curation step so an editor can approve the line-up first.
Deliverability and analytics, built in
- Open and click tracking, with automatic UTM tagging for Google Analytics or Plausible
- Per-campaign analytics — opens, clicks, CTR, click-to-open, bounces, complaints, and unsubscribes
- A pre-send spam-score check flags deliverability problems before you hit send
- Automatic bounce handling and a global suppression list, so you stop emailing dead addresses
- First-class adapters for SendGrid, Postmark, Mailgun, and Resend — or any SMTP relay — with bounce and complaint webhooks included
Transactional email too
Confirmation, welcome, unsubscribe, and re-subscribe emails are first-class, fully editable, and rendered with the same personalisation engine as your campaigns — so your automated mail looks as good as your broadcasts.
Try it free
Forms and submissions are free to evaluate — build forms and collect submissions with no licence key at all. The email features (campaigns, newsletters, digests, and transactional mail) require a licence; on localhost and development environments they unlock automatically for a 14-day trial, so you can take the whole platform for a spin before you buy. Purchase and manage your licence at projects.datapad.nl.
Requirements
- Umbraco 17.x
- .NET 10
- SQLite or SQL Server
Install
dotnet add package CampaignCanvas
On first start the package registers its backoffice section, content apps, and runs its schema migrations automatically.
Licence key
See https://projects.datapad.nl/projects/campaigncanvas for licence-key installation instructions.
Support
Questions and support requests: https://projects.datapad.nl/projects/campaigncanvas.
Updates
1.2.6
- Fix — Google reCAPTCHA v3 could block a form submit with a console error, or silently never send: when reCAPTCHA was enabled, the front-end called
grecaptcha.readyas soon as the visitor hit submit. If Google's script hadn't finished loading — it is fetchedasync defer— that threw in the console and the form never posted. When the script was already loaded, the follow-uprequestSubmit()ran in the same submit event and the browser ignored it, so the click appeared to do nothing. The form now waits forgrecaptcha.executewithout stubbing Google's object, defers the real post until the current submit event has finished, and shows a form-level error if the script fails to load or the token is rejected — including server-side captcha failures that previously re-rendered the page with no message.
1.2.5
- CampaignCanvas now plugs into Umbraco Automate: a companion package, CampaignCanvas.Automate, puts your forms and contacts into Automate's visual automation builder. Four triggers start an automation — Form Submitted, Contact Created, Contact Subscribed to List, and Contact Unsubscribed from List — and four actions let any automation act on your contacts: Find Contact by Email, Create or Update Contact, Subscribe Contact to List, and Unsubscribe Contact from List. Pick a form on the Form Submitted trigger and its fields become real bindings, so a later step can reference an answer as
${ trigger.fields.email }without you parsing anything. The contact triggers can be narrowed to a single mailing list, subscribe honours each list's double-opt-in setting and records a consent source for your audit trail, and bulk imports still stay silent so a 50,000-row import can't spawn 50,000 automation runs. Because a bound field can carry whatever a visitor typed into a public form, the steps assume exactly that: a contact who unsubscribed from a list or whose address bounced is left alone rather than quietly re-subscribed, consent an automation writes is stamped with that automation's id so it can never be mistaken for consent a person gave, and every contact trigger skips events its own automation caused — so an automation that both listens for and performs the same change can't feed itself. It's a separate install (dotnet add package CampaignCanvas.Automate) and needs Umbraco Automate plus Umbraco 17.4 — nothing changes for sites that don't want it. - Send a content-page newsletter in every language your site speaks: on a multilingual site, the Newsletter tab of a page now carries a language picker, and each language is sent as its own newsletter — its own recipients, its own opens and clicks, its own row under Campaigns with the language shown against it. Previously a page could only be mailed once no matter how many languages it existed in: sending the Dutch version marked the whole page as sent and locked the English one out entirely. Worse, because a send runs in the background with no browser request behind it, there was no language in context to render from, so a newsletter quietly came out in the site's default language whichever variant you thought you were sending — links, titles and any content it pulled in all included. The picker opens on the language you're already editing in, only offers variants that are actually published, and pages that don't vary by culture still get one send per language so their links resolve correctly. Digest campaigns carry a language too. Newsletters you sent before upgrading are stamped with your site's default language on first run, so nothing that has already gone out becomes sendable again.
- Fix — an activated licence could vanish on deployment and silently restart your trial: the licence key lived only in
umbraco/Licenses/CampaignCanvas.key, which any deployment that replaces the content root wipes — run-from-package, container rebuilds, sync-with-delete, slot swaps — and on a load-balanced site it only ever existed on the one node it was typed into. The failure was invisible: with the trial-state file wiped alongside it, the site issued itself a fresh 14-day trial and carried on, then stopped sending a fortnight later for no apparent reason. The key now lives in the database, which survives redeployment and is shared by every node. Existing installs adopt their key file automatically on upgrade — there's nothing to re-enter — andCampaignCanvas:LicenseKeyinappsettings.jsonor an environment variable still takes precedence if you'd rather pin it there. - Fix — running out of Vouch credits mid-clean wrote off the addresses it never got to: when a Clean list run exhausted your credits partway through a batch, the addresses Vouch had accepted but never actually attempted were recorded as though they'd been checked and come back inconclusive. The run itself halted correctly and told you credits had run out — but topping up and re-running then skipped those very addresses, because they now counted as already-verified, leaving the opt-in "also re-verify previously-inconclusive addresses" checkbox as the only way to reach them. Addresses a credit-exhausted batch never attempted are now left unverified, so a re-run after a top-up carries on exactly where the last one stopped and every address in scope still gets a real verdict.
1.2.4
- Trigger your own automations on contact activity — straight from Umbraco's Webhooks: CampaignCanvas now adds three events to Umbraco's built-in Settings → Webhooks picker — Contact Created, Contact Subscribed to List, and Contact Unsubscribed from List — so you can POST contact activity to Zapier, Make, a CRM, or your own endpoint with no code and no form to hang a workflow on. A subscribe fires the moment a contact becomes genuinely active — immediately on single-opt-in lists, or on the confirmation click for double-opt-in — and an unsubscribe carries the reason where one was given. Umbraco handles the delivery, retries, custom headers, and logging you already know.
- Every subscribe/unsubscribe payload includes the contact's full list picture: alongside the contact's details and the list that triggered the event, the payload carries a
listsarray of every mailing list with that contact's status on it (Subscribed,PendingConfirmation,Unsubscribed,Bounced, orNonewhen they're not a member) — so the receiving system can mirror the complete subscription state in a single call instead of asking back. Bulk imports and bulk list changes deliberately don't fire these per contact, so a 50,000-row import can't storm your endpoint.
1.2.3
- Contact CSV export now records each address's verification status: the Export contacts to CSV download gains a
VerificationStatuscolumn, so every exported contact carries its latest Vouch verdict —Deliverable,Undeliverable,Risky, orUnknownfor addresses not yet checked — right alongside the existing bounce columns. It makes list health easy to filter, report on, or hand to another system without opening the backoffice, and it's populated for suppressed contacts too so you keep the complete picture.
1.2.2
- Re-verify addresses Vouch couldn't reach a verdict on: some addresses come back inconclusive ("Unknown") from a clean — the mailbox server gave no clear answer, usually a temporary block, greylisting or timeout rather than a genuinely bad address. These are skipped on later cleans so you're never charged twice, but that left no way to try them again. The Clean list dialog now offers an opt-in "Also re-verify N previously-inconclusive addresses" checkbox: leave it unticked to verify only never-checked contacts as before, or tick it to re-check the inconclusive ones too. The estimated cost and credit check update to match your selection, so you always see the exact charge before starting — nothing is ever re-verified silently.
1.2.1
- Fix — Clean list over-counted the contacts it would verify, and the credits it would cost: the pre-flight estimate counted your whole contact base instead of only the addresses still needing a check, so a mostly-clean list quoted a charge for everyone — a list of thousands could report thousands of credits (and warn you were short) when only a few hundred addresses were actually unverified. Already-verified contacts are now correctly skipped in both the estimate and the run itself, so the cost shown matches what you're charged, and re-running Clean list never re-verifies — or re-bills for — an address that was already checked on an earlier run.
1.2.0
- New — know exactly who you're mailing, with email verification by Vouch: every mailing list quietly rots — people change jobs, abandon inboxes, mistype their address on signup — and every dead address you keep mailing chips away at your sender reputation until real subscribers stop seeing you. CampaignCanvas now plugs straight into vouch.fast, which verifies addresses at the actual mailbox: a live SMTP conversation with Gmail, Outlook and the rest, not just a syntax pass. Setup is one paste — grab a
vch_live_…key from the Vouch dashboard, drop it into Subscribers → Email verification, and it's validated and stored in your site'sappsettings.jsonfor you. Live instantly; no restart, no config-file surgery. - Clean your whole list in one click: the new Clean list action verifies your entire contact base (or a single mailing list) with live progress in the backoffice. Every subscriber gets a verdict — deliverable, undeliverable or risky — plus the reason (mailbox not found, no mail server, disposable domain, …), the grid filters by verdict, and definitively dead addresses go straight to the suppression list so every future send skips them automatically. Cleaner list, fewer bounces, better inbox placement for every campaign that follows.
- Start with a free list health check: every Vouch key includes one free, no-credit health check — a structural diagnosis of your whole contact base that tells you how bad the rot is before you spend anything ("18% of your subscribers look undeliverable or problematic"), broken down by cause. Percentages only — the full clean is what names names. It's the fastest way to see what Vouch can do: mint a free key at vouch.fast and run it today.
- Fair, transparent credits: verification runs on prepaid Vouch credits — roughly a cent per address, cheaper in volume, no subscription. CampaignCanvas shows the estimated cost against your live balance before a run starts and halts safely if credits run out. It's also deliberately cautious with your data: an ambiguous result never marks an address undeliverable, "risky" addresses are never removed automatically, and if Vouch is ever unreachable your signups and sends carry on untouched.
- Much faster SMTP sending on large lists: a send now holds one authenticated SMTP connection open across a whole batch instead of reconnecting for every single message. The TCP handshake, TLS negotiation and
AUTHexchange used to be repeated per recipient, and on a list of tens of thousands that handshake — not the message itself — was the bulk of the time a send took. Nothing else about delivery changes: the same message is built, signed and classified exactly as before, a per-recipient rejection leaves the shared connection healthy, and a network fault simply reconnects on the next message. Sending through an HTTP-based provider (SendGrid, Mailgun, Postmark, Resend) is unaffected — those already pool their connections. Worth knowing: throughput is still capped byCampaignCanvas:Newsletter:Send:MaxMessagesPerMinute, which defaults to a deliberately cautious 100/min suited to a basic SMTP server. If you send through an ESP that permits more, raise that setting — it's what turns the saved handshakes into a genuinely faster send. - Fix — "which lists would you like?" answers showed raw ids in notification emails and CSV exports: when a form used a mailing-list checkbox or preferences field, the new-submission notification and the submissions CSV printed the selected lists' internal ids — a row of GUIDs — instead of the lists the person actually ticked, so the answer was unreadable without looking each id up. These now render as the list names, taken from the labels already stored on the field. Every other field type is unchanged, and nothing was lost from existing data: the selections were always recorded, so re-exporting an older submission now shows its lists by name too. (Notification emails already delivered can't be rewritten — the fix applies to submissions received from this version onward.)
- Dependency update — MailKit 4.15.1 → 4.17.0: updates the SMTP delivery library to pick up the fix for a published security advisory.
1.1.19
- Fix — multi-choice fields showed
System.String[]in submission emails and CSV exports: when a form had a checkbox-list or multi-select field (for example "which newsletters would you like?"), the new-submission notification email and the submissions CSV export printed the literal textSystem.String[]in that row instead of the options the person ticked — so you couldn't tell what they'd actually chosen. These fields now render as a comma-separated list of the selected values. Single-value fields are unchanged, and nothing was lost from existing data: every choice was already stored, so re-exporting an older submission now shows its values correctly too. (Notification emails already delivered can't be rewritten — the fix applies to submissions received from this version onward.)
1.1.18
- Bounced addresses are now suppressed automatically, however the bounce is reported: when a mailbox permanently rejects a message, that address is counted against its hard-bounce tally and — once it crosses the threshold (3 by default) — added to the suppression list, so it's skipped on every future send. Previously this only happened when your provider rejected the message at the moment of sending; bounces reported a few minutes later over a provider webhook — the usual case for SendGrid, Mailgun, Postmark and Resend — appeared in analytics but never stopped the address being mailed again. Continuing to email dead addresses quietly erodes your sending reputation, so this protects deliverability for your whole domain.
- Hard and soft bounces are now told apart for every provider: SendGrid and Resend reported all delivery failures as a single generic "bounce", mixing permanent failures (a bad address) with temporary ones (a full mailbox, a greylisting deferral). They're now classified the same way Mailgun and Postmark already were — only genuinely permanent failures count toward auto-suppression, and your per-campaign hard/soft bounce breakdown is accurate.
1.1.17
- Unsubscribes are now counted against the campaign that drove them: opting out via the unsubscribe link or the preferences page now registers on the originating mailing's "unsubscribed" figure. Previously a campaign only counted the opt-outs your email provider reported back, so unsubscribes through the built-in link and preferences form were invisible in per-campaign analytics. The opt-out link now carries the send it came from, and repeated one-click hits (mail-client prefetch plus the manual confirm) are de-duplicated so the count stays accurate.
- Email a list owner when someone unsubscribes: every mailing list can now hold one or more notification addresses (Mailing list editor → Notifications). When a contact unsubscribes through the public link, those addresses receive an email naming the contact, the list, and any reason given; leave the field blank to keep it off. The preferences form could already notify via its email-notification workflow — this brings the same alert to the direct unsubscribe link, which has no workflow to hang one on.
1.1.16
- Marketplace listing refresh: the package description and README have been rewritten into clearer, benefit-led copy covering the full forms + newsletter platform, with extra discovery tags (
newsletters,email-marketing,gdpr). No functional changes — this release exists to publish the updated listing. - Docs — corrected licence-key link: the Licence key section pointed at
campaigncanvas.netfor installation instructions; it now points at the Datapad customer portal (projects.datapad.nl/projects/campaigncanvas), matching the purchase and support links.
1.1.15
- Fix — an expired trial could still display as "Active": the License page and banner decided "active" from a cached flag without re-checking the expiry date, so a lapsed trial could show "Active" next to "Expired". An expired trial now correctly reads as inactive — so the genuine licence state, and any activation issue behind it, is no longer hidden.
- Clearer activation failures: entering a licence key that can't be validated no longer silently reverts to the trial. The page now states the reason — and an unlicensed domain reads "Domain 'X' isn't on this license yet. Add it in the portal at projects.datapad.nl, then click Refresh." instead of a generic message.
- Diagnostics: when a validation response is rejected as outside the freshness window, the log now records the response's
issuedAtand this server's current time, so a clock / time-sync problem on the host is obvious at a glance.
1.1.14
- Maintenance: licensing reliability and internal housekeeping.
- Backoffice: the CampaignCanvas dashboard now shows the installed package version, so it's easy to confirm which build a site is running.
- Licensing: licence validation now reports the running Umbraco and CampaignCanvas versions to the licensing service, so compatibility guidance stays accurate.
1.1.13
- Fix — newsletter settings page on SQL Server: the migrations that add the preferences-link and subscription-pages columns to the newsletter settings row used
ALTER TABLE ... ADD COLUMN ..., which is valid SQLite syntax but invalid on SQL Server (SQL Server'sALTER TABLE ADDdoes not accept theCOLUMNkeyword). On SQL Server installs upgrading from 1.1.11 or earlier, the migration silently failed inside the startup upgrader and the newsletter settings page then errored withInvalid column name 'includePreferencesLink' / 'preferencesPageUrl' / 'subscriptionPagesJson'. The migrations now emit the keyword-freeALTER TABLE T ADD col TYPEform, which is valid on both providers. Every otherADD COLUMNmigration in the plan got the same correction so future upgrades from intermediate versions don't hit the same trap.
1.1.12
- Preferences link in campaigns: outbound campaigns can now carry a "manage your email preferences" link in the footer alongside the existing unsubscribe link. Enable it from Newsletter settings and point it at a content page that hosts a preferences form — the link is signed per-subscriber, so the destination form consumes the token and writes back to the right subscription record.
- Mailing-list checkboxes form field: new field type that renders one checkbox per configured mailing list and stores the ticked ids on the submission. Paired with the existing "Add to mailing list" workflow so a single form can opt a submitter into several lists at once, with the labels captured at edit-time so renames don't break public pages.
- Resubscribe after unsubscribe: the unsubscribe-success page now offers a one-click resubscribe path back into the same list. The link is a signed, single-purpose token (separate from the unsubscribe token) so an accidental unsubscribe is reversible without re-confirming via double-opt-in.
- Editable copy for lifecycle pages: every subscriber-facing page served by the newsletter controller — confirm-success, unsubscribe form + success, resubscribe form + success, invalid-token — now has editable heading / body / button-label slots in Newsletter settings. Blank slots fall through to the built-in defaults so editors can override only the strings they care about. The
{listName}placeholder is substituted at render time. - Fix — emails referencing
https://localhost: logos, unsubscribe, preferences, open-pixel, and click-redirect URLs in dispatched campaigns now resolve to your public host. The background send worker has no HTTP context to derive a base URL from, so the public URL builder now falls back to Umbraco'sWebRouting:UmbracoApplicationUrlconfiguration. ConfigureUmbraco:CMS:WebRouting:UmbracoApplicationUrlinappsettings.jsonfor this to take effect.
1.1.11
- Licensing: licence validation now talks to the Datapad Licensing service (
projects.datapad.nl). All purchase, support, and "manage your licence" links route through the customer portal atprojects.datapad.nl/projects/campaigncanvas. - Hardening: the on-disk licence cache stores the raw signed envelope and verifies its Ed25519 signature on every load. Tampered cache files are discarded; legacy plaintext caches are migrated transparently.
- Backoffice: swept deprecated Umbraco backoffice APIs (
auth.getLatestToken(),UmbPropertyValueChangeEvent) so the package stays compatible with upcoming Umbraco releases.
1.1.10
- Fix: custom Block Grid components in newsletters now render in the spot you placed them. The newsletter dispatcher sets a
CampaignCanvas.IsNewsletterRenderViewData flag so host partials can emit table-row markup (<tr><td>…</td></tr>) for the email's outer table while keeping their normal page markup elsewhere. Previously, partials that emitted non-table HTML were hoisted out of the email's outer<table>by the browser and appeared above the email card.
1.1.9
- Fix: trial countdown now persists across app restarts and the 24-hour licence-cache refresh, so the banner correctly ticks down from 14 days instead of re-anchoring to "now" on every refresh.
- Hardening: the persisted trial-state file is HMAC-signed, so manual edits to the start date are detected and the trial falls back to unlicensed instead of silently extending.
Licence
This package is licensed under a commercial End User License Agreement; see LICENSE.txt. Redistribution, reverse engineering, and circumvention of the licence-key check are prohibited.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- HtmlSanitizer (>= 9.0.892)
- MailKit (>= 4.17.0)
- NSec.Cryptography (>= 25.4.0)
- Umbraco.Cms.Api.Common (>= 17.3.2)
- Umbraco.Cms.Api.Management (>= 17.3.2)
- Umbraco.Cms.Core (>= 17.3.2)
- Umbraco.Cms.Infrastructure (>= 17.3.2)
- Umbraco.Cms.Web.Common (>= 17.3.2)
- Umbraco.Cms.Web.Website (>= 17.3.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.2.6 | 0 | 8/27/2026 |
| 1.2.5 | 116 | 7/31/2026 |
| 1.2.4 | 122 | 7/15/2026 |
| 1.2.3 | 117 | 7/14/2026 |
| 1.2.2 | 115 | 7/14/2026 |
| 1.2.1 | 119 | 7/14/2026 |
| 1.2.0 | 124 | 7/9/2026 |
| 1.1.19 | 140 | 6/18/2026 |
| 1.1.18 | 121 | 6/10/2026 |
| 1.1.17 | 121 | 6/9/2026 |
| 1.1.16 | 120 | 6/2/2026 |
| 1.1.15 | 122 | 6/1/2026 |
| 1.1.14 | 125 | 5/29/2026 |