Skip to main content

Email Campaigns

Bellamy Book includes an Email Campaigns feature for administrators to create and send bulk marketing or announcement emails to users. Campaigns can be scheduled for a future time or sent after you generate the recipient queue. The feature is license-gated and uses a background job (Quartz) to send emails in batches.

License

Email Campaigns is a license-gated feature. It is only available when the emailCampaigns feature flag is enabled (typically Tier 2 or Tier 3). Some tiers apply a rate limit (e.g. 500 emails per month); Tier 3 may allow unlimited usage.

How it works

  1. Create campaign — Admin creates a campaign with name, subject, body (plain or HTML), optional scheduled time, and option to include blog file download recipients.
  2. Generate queue — Admin triggers Generate queue for a campaign. The system builds the recipient list:
    • All users with a verified email
    • Optionally, emails from Blog File Download (users who downloaded blog files), if Include blog file download emails was checked when creating/editing the campaign
      Duplicate emails are deduplicated (one email per address per campaign).
  3. Sending — The EmailCampaignJob (Quartz) runs on a cron schedule (default: every minute). It finds campaigns that are Scheduled or Draft with ScheduledAt in the past, marks them as Sending, and sends pending emails in batches (e.g. 50 per run) via the application’s email sender.
  4. Completion — When all queued emails for a campaign are processed (sent or failed), the campaign status becomes Completed (or Failed if the job marked it as failed).

Campaign statuses

StatusDescription
DraftCreated, no schedule or schedule in the past; not yet sending.
ScheduledHas a future ScheduledAt; job will start sending when that time is reached.
SendingJob is currently sending emails for this campaign.
CompletedAll queued emails have been processed (sent or failed).
CancelledAdmin cancelled the campaign (only from Draft/Scheduled/Sending).
FailedJob marked the campaign as failed (e.g. critical error).

Admin Panel

Email Campaigns are managed in the Admin Panel under Notifications → Email Campaigns (visible when emailCampaigns is enabled).

  • Route: /notifications/email-campaigns

Tabs

  1. Campaign list — Paginated list of campaigns (name, subject, status, scheduled time, total/sent/failed counts). Actions: Cancel (Draft/Scheduled/Sending), Delete, Generate queue (Draft/Scheduled, once per campaign).
  2. Create campaign — Form: name, subject, body, HTML checkbox, scheduled date/time, Include blog file download emails. Submit creates a campaign (Draft or Scheduled).
  3. History — Paginated list of sent emails per campaign. Filters: campaign ID, campaign name, recipient email.

Typical workflow

  1. Create a campaign (name, subject, body, optional schedule, optional “include blog file download emails”).
  2. Optionally set Scheduled at for future send time.
  3. Click Generate queue for that campaign (recipients are computed and stored; each campaign can have its queue generated only once).
  4. If scheduled, the job will start at that time; otherwise the job will pick it up on the next run (e.g. within a minute) if ScheduledAt is in the past or null.
  5. Monitor status and History for sent/failed counts.

API Endpoints

All endpoints are under api/EmailCampaign and require Admin role. License enforcement applies to write operations (create, generate-queue); the feature must be enabled and within limits.

MethodEndpointDescription
GET/api/EmailCampaignList campaigns (query: skip, take, status)
GET/api/EmailCampaign/{campaignId}Get campaign by ID
GET/api/EmailCampaign/historyGet email history (query: campaignId, campaignName, recipientEmail, skip, take)
POST/api/EmailCampaignCreate campaign (body: name, subject, body, isBodyHtml, scheduledAt?, includeBlogFileDownloadEmails)
PUT/api/EmailCampaign/{campaignId}Update campaign (same body as create; only Draft/Scheduled)
POST/api/EmailCampaign/{campaignId}/cancelCancel campaign (Draft/Scheduled/Sending)
POST/api/EmailCampaign/{campaignId}/generate-queueGenerate recipient queue (once per campaign; returns totalEmailsGenerated)
DELETE/api/EmailCampaign/{campaignId}Delete campaign and its queue

Create/Update body

  • name (required, max 200)
  • subject (required, max 500)
  • body (required)
  • isBodyHtml (boolean, default true)
  • scheduledAt (optional, ISO date-time; if set in the future, status is Scheduled)
  • includeBlogFileDownloadEmails (boolean, default false) — include emails from blog file downloads in the queue

Background job

  • Job: EmailCampaignJob (Quartz, in-process).
  • Schedule: Configurable via Quartz:EmailCampaignJob (default: every minute, e.g. 0 * * ? * *).
  • Behavior: Loads campaigns that are ready to send (Scheduled/Draft with ScheduledAt ≤ now), marks them Sending, fetches pending email queue entries (batch size e.g. 50), sends each email via IEmailSender, updates queue and campaign counts; marks campaign Completed or Failed when done.