Get Hedhog updates in your inbox
New releases, fresh recipes, and breaking changes — no spam.
Campaign Submodule
templates
Manages reusable email content templates (name, subject, HTML/plain-text body) that campaigns can reference.
Source path: libraries/campaign/src/services/campaign-template.service.ts
Module file: campaign.module.ts
Introduction
The Templates submodule provides a small, self-contained content library — `campaign_template` rows — that campaigns reference by `template_id` instead of duplicating subject/body text in every campaign. Each template carries a name, an optional slug, an optional description, a subject, an HTML and/or plain-text body, a `content_type` flag ("html" | "text"), and a `status` ("active" | "inactive") used to hide retired templates from pickers without deleting their history.
At send time, CampaignEmailWorkerService only falls back to a template's stored subject/body when the campaign itself has no inline `content_html`/`content_text` or `subject` — the campaign's own fields always take precedence. This lets a campaign either fully own its content or delegate to a shared template, and lets a single template be reused by multiple campaigns simultaneously since the resolution happens per-send rather than by copying the template content into the campaign record at creation time.
CampaignTemplateService also retains a backward-compatible bridge into the Core Mail submodule (`getMailTemplates` / `getSnapshot`), reading from the shared `mail` / `mail_locale` / `mail_var` tables. This lets older integrations that expected campaign templates to live in Core's mail template tables continue to resolve subject/body and variable lists, even though new template authoring happens through `campaign_template`.
Every create, update, and delete on a template publishes a `campaign.template.*` domain event through the Integration submodule's outbox, allowing other parts of the platform (or external systems via webhooks) to react to template lifecycle changes without polling.
The `send-test` endpoint on this submodule is a thin placeholder: it resolves the template by ID and returns an acknowledgement message without actually sending mail, unlike the campaign-level and recipient-list-level test-send endpoints, which do enqueue a real delivery through `CampaignDispatchService`.
HTTP Endpoints
7 endpoints
Paginated list of campaign templates.
- Query
- page, pageSize, search, status
Create a new email template. Publishes a campaign.template.created event.
Body
| Field | Type | Required | Notes |
|---|---|---|---|
| name | string | yes | — |
| slug | string | no | Unique identifier slug |
| description | string | no | — |
| subject | string | no | Email subject line |
| content_html | string | no | HTML email body |
| content_text | string | no | Plain-text fallback body |
| content_type | "html" | "text" | no | Default: "html" |
| status | "active" | "inactive" | no | Default: "active" |
Bulk delete templates. Publishes a campaign.template.deleted event.
Body
| Field | Type | Required | Notes |
|---|---|---|---|
| ids | number[] | yes | IDs to delete |
Get a template by ID.
- Params
- id (int)
Update a template. Only provided fields are changed. Publishes a campaign.template.updated event.
- Params
- id (int)
Body
| Field | Type | Required | Notes |
|---|---|---|---|
| name | string | no | — |
| slug | string | no | — |
| description | string | no | — |
| subject | string | no | — |
| content_html | string | no | — |
| content_text | string | no | — |
| content_type | "html" | "text" | no | — |
| status | "active" | "inactive" | no | — |
Delete a single template.
- Params
- id (int)
Resolve the template by ID and return an acknowledgement message. Placeholder endpoint — does not actually dispatch an email.
- Params
- id (int)
Body
| Field | Type | Required | Notes |
|---|---|---|---|
| string | yes | Recipient of the test email | |
| name | string | no | Recipient display name |