Building and sending a campaign

Picking recipients from your own user list, the emails-per-hour throttle and what it really costs, the six campaign states, retrying only what failed, and the 10,000-character recipient ceiling that decides how you have to structure sends.

9 min readUpdated 3 August 2026campaigns, recipients, sending, retry

A campaign is four things: a name, a subject line, a template, and a list of people. Everything else is a throttle and a status.

Campaigns live at Admin → MailWizard → Campaigns, /admin/mailwizard/campaign.

Creating one

  1. Campaigns → Create — the page splits into settings on the left and the recipient list on the right.

  2. Name and subject — the name is internal, the subject is what the recipient sees. Both are required and both cap at 191 characters.

  3. Emails per hour — the send throttle. Read the next section before you pick a number; the field shows you the projected finish time as you type.

  4. Template — the dropdown lists every template on the install. The first one is pre-selected, so check it rather than assuming.

  5. Add Targets — the recipient picker. See below; this is the step with the traps.

  6. Create Campaign — the button stays disabled until name, subject, template and at least one recipient are present. A campaign with no recipients cannot be created from this screen, which is deliberate: it would sit ACTIVE and send nothing forever.

A new campaign is created in PENDING. It does not send until you deliberately start it.

Choosing recipients

The Add Targets dialog browses the platform's own user table. There is no separate subscriber list, no import, and no concept of a segment — the audience is whatever you tick, copied onto the campaign as a snapshot.

Search matches first name only. The search box filters on firstName with a starts-with match. Typing an email address, a surname or a partial name from the middle returns nothing, which reads exactly like "this user does not exist".

Select all does not work. It fetches a lightweight user list that carries no email addresses, so every recipient it adds has a blank address. Saving the campaign is then refused with "targets[0] is missing an email address". Tick recipients individually.

It needs the view.user permission. That is a core CRM permission, not a MailWizard one. Without it the dialog lists nobody and says nothing.

Each recipient is stored on the campaign with the profile fields the picker handed over, plus a delivery status. Removing a recipient is only possible while they are still PENDING — the small × on the card disappears once an address has been attempted, because deleting the record of a send does not un-send it.

The recipient ceiling

The recipient list is stored as a JSON string in a single column on the campaign row, and that field is validated at 10,000 characters. Recipients ticked in the picker carry their entire user profile — roles, verification flags, sign-in timestamps — at several hundred characters each.

Over the limit, saving fails with "Targets must be no more than 10000 characters long." and the campaign is neither created nor updated.

This applies to editing as well. A campaign that already holds a longer list cannot be saved at all — not even to correct its name. The recipients already stored keep sending; only saving is blocked.

Two ways to live with this:

  • Split the audience. Several campaigns against the same template, each with a manageable list, is the supported shape. It also gives you a natural way to stagger sends across hours.
  • Write the list through the targets endpoint. PUT /api/admin/mailwizard/campaign/{id}/target replaces the recipient list and is the one write path with no length cap — it validates the shape of the list (an array of objects, each with a usable email address) but not its size, up to a structural ceiling of 100,000 recipients. Send only the fields you need — id, email, firstName, lastName, status — and a list of several thousand fits comfortably. See the API reference.

Do not paste a hand-built list into the campaign form and hope. An unusable list stored on a campaign used to abort the entire send run for every other campaign on the platform; that is fixed, but a bad list now gets the campaign auto-paused instead, which is quieter than it sounds.

Emails per hour

speed is a budget per send run, and the send run happens once an hour. So the number in that field is also the per-hour rate, and the arithmetic matters more than it looks:

Recipients Speed Finishes in
50 50 1 hour
500 50 10 hours
1,000 10 100 hours — about 4 days
5,000 100 50 hours — about 2 days

The form does this for you, showing the estimate under the field and computing it from the recipients still pending rather than the total, so on a part-sent campaign it reflects the work actually left. Above a day it also raises a warning, because that is the threshold worth interrupting somebody for.

Pick the number your mail provider will tolerate, not the number you wish were true. A shared SMTP account throttled mid-run turns pending recipients into failed ones, and the send job's protection against that costs you a whole hour's worth of the list — see How sending works.

A speed below 1 is refused by the API, and a campaign that somehow holds one is paused by the send job rather than left ACTIVE and silently idle.

The six campaign states

Status Meaning Does the send job look at it?
PENDING Created, never started No
ACTIVE Sending Yes — this is the only status that sends
PAUSED Stopped mid-send, recipient statuses untouched No
STOPPED Stopped and every recipient reset to pending No
COMPLETED No recipient is still pending No
CANCELLED Abandoned deliberately No

Recipients have a different, three-value vocabulary — PENDING, SENT, FAILED — and conflating the two is the classic mistake with this addon. A campaign can be COMPLETED with every recipient FAILED.

Controls on the campaign page

Five buttons, and the difference between two of them is the one thing to get right.

  • Start — sets ACTIVE. The next hourly run picks it up; nothing happens instantly.
  • Pause — sets PAUSED. Recipients keep whatever status they had. Starting again resumes exactly where it left off.
  • Retry failed — re-queues only the recipients that failed, and reactivates the campaign. Delivered recipients are untouched.
  • Stop — sets STOPPED and resets every recipient to pending. Starting again re-sends to everybody, including everyone who already received the email.
  • Cancel — sets CANCELLED. A dead end by design; retrying will not override it.

Stop exists to run a campaign again from the beginning, so it resets the whole list. On a campaign that has already delivered anything, pressing it means everybody gets the email a second time.

The interface asks first and the confirmation names how many people that is. Take the number seriously — a duplicate marketing send does more damage to a sending domain than the failures you were trying to fix.

If you only want to stop it now, use Pause.

Stop remains available on a COMPLETED campaign on purpose: finishing is exactly when you discover a campaign needs re-sending, and leaving every control disabled made a completed campaign a dead end.

Recovering from failures

A finished campaign with a handful of failures is the normal case, not an emergency. Retry failed is the right tool.

  1. Find out who failed — the progress panel's failed count is clickable and filters the recipient list to exactly those addresses.

  2. Read why — each failed recipient card carries the reason recorded by the mail transport and how many times that address has been attempted. A connection error is worth retrying; "550 no such user" is not.

  3. Retry — the button re-queues the failed recipients and reactivates the campaign so the next hourly run picks them up.

Each address may be attempted three times. Beyond that, retry declines and tells you how many are exhausted. That cap is not arbitrary: a mailbox that no longer exists answers the same way every time, and hammering dead addresses is precisely what wrecks a sending domain's reputation.

A failed recipient with no email address at all is never retried — nothing can make that attempt succeed.

Editing a running campaign

The campaign page loads the recipient list when you open it and posts the whole list back on every save. Meanwhile the send job is rewriting that same list as it works.

Saving a campaign that has been sending since you opened the page overwrites the job's progress with your stale snapshot — recipients already delivered to go back to PENDING, and the next run emails them again.

Pause the campaign, reload the page, make the change, then start it.

Editing applies the same validation as creating: a speed below 1 is refused, a template that has since been deleted is reported as not found, and the recipient list is checked for shape and size. An edit can therefore fail where it used to succeed on older builds.

Bulk operations

The Campaigns list lets you select several rows and delete them together. Bulk status changes exist in the API but have no button on the screen — if you drive them from a script, two cautions apply:

  • A bulk change to ACTIVE starts every selected campaign. They all begin sending on the next hourly run, and their throttles add up against a single mail account.
  • Bulk STOPPED does not reset recipients. The single-campaign status route performs that reset; the bulk route writes the status only. So a bulk stop behaves like a pause, which is safer but is not what the word implies.

Deleting a campaign takes its recipient list and delivery history with it. There is no per-recipient record anywhere else — no separate log, no report, nothing to recover it from.

Reading progress correctly

The progress bar measures attempts, not deliveries — sent plus failed over the total. That is why the caption alongside it always states both figures: "100% attempted, 640 of 1000 delivered, 360 failed" is not a successful campaign, and one percentage would hide it.

Remember the ceiling on what any of this can tell you. SENT means the mail transport accepted the message. It does not mean the message was delivered, it does not mean it reached an inbox rather than a spam folder, and it certainly does not mean anybody read it — there is no open or click tracking in this product at all.

Next: How sending works for the job, the transport and deliverability, or Troubleshooting when a campaign says Active and does nothing.