Troubleshooting

A campaign that says Active and sends nothing, saves that are refused, an empty recipient picker, blank emails, mass failures and duplicate sends — the cause of each and the fix.

7 min readUpdated 3 August 2026troubleshooting, cron, smtp, deliverability

Almost every MailWizard problem is silent. The screens report success, the campaign says Active, and nothing arrives. Work through this page in the order given — the first two sections cover most of it.

A campaign is Active and nothing is sending

Check these in order. Each one is a complete explanation on its own.

Campaigns are sent by a scheduled job and by nothing else. If the cron PM2 app is stopped or crashed, every campaign sits at ACTIVE and 0% indefinitely, and no MailWizard screen says so.

Check pm2 list for a cron entry in online status, then pm2 logs cron. The Campaigns screen has one indicator: Stalled Sends counts ACTIVE campaigns untouched for over an hour. On a healthy install that is zero. See Processes and ports.

The job runs every sixty minutes. Setting a campaign to Active makes it eligible; it does not send anything at that moment. Trigger processMailwizardCampaigns manually at /admin/system/cron if you need it now.

An ACTIVE campaign with an empty list stays ACTIVE forever and sends nothing. The campaign view dialog badges this as No recipients, and the send job logs "No targets found".

This normally means the recipient list was lost on save rather than never added — see the saving is refused section below.

Disabling mailwizard at /admin/system/extension deregisters the send job within about a minute. Campaign rows are untouched, so an ACTIVE campaign simply stops progressing with no visible change.

The campaign page shows the status it last wrote, and it does not poll. Reload the Campaigns list and read the status from the table instead. A campaign the send job paused itself — for an unreadable recipient list or a speed below 1 — shows as PAUSED there.

The job only looks at PENDING recipients. A campaign whose list is entirely resolved should have flipped to COMPLETED; if it is still ACTIVE, the completion write failed and the cron log will say so.

The send job paused my campaign by itself

The job pauses a campaign rather than retrying it forever in two situations, because a visible pause beats invisible failure. Both write the reason to the cron log.

Reason Fix
The recipient list cannot be read as a list Re-add the recipients and reactivate. A list written by hand or by an old build is the usual cause
The sending speed is not a positive number Set Emails per hour to at least 1 and reactivate

Neither can happen through the current admin screens — both write paths validate now — but rows written before that validation existed are still out there.

Saving a campaign is refused

The recipient list is capped at 10,000 characters of stored JSON. Recipients ticked in the picker carry their entire user profile, so this is reached at roughly fifteen of them.

It blocks editing as well as creating: an existing campaign holding a longer list cannot be saved at all, not even to correct its name. The recipients already stored keep sending; only saving is blocked.

Fix: split the audience across several campaigns, or write the list through PUT /api/admin/mailwizard/campaign/{id}/target, which has no size cap. See the API reference.

Other refusals and what they mean:

Message Cause
targets[0] is missing an email address Almost always Select all in the recipient picker — it adds recipients with blank addresses. Tick recipients individually
targets must be a JSON array of recipients The list was posted as something other than an array of objects
speed must be a whole number of emails per hourly send run, at least 1 The throttle is below 1 or not an integer
Template not found The template this campaign points at has been deleted. Pick another one
name is required / subject is required Blank, or whitespace only

The recipient picker is empty

Three causes, in order of likelihood.

The search matches first name only. The box filters on firstName with a starts-with match. An email address, a surname, or a name fragment from the middle returns nothing — which looks exactly like the user not existing. Search by the beginning of the first name, or page through the list.

The role lacks view.user. The picker reads the platform's user list through a core CRM endpoint gated by view.user, not by any MailWizard permission. A role with every MailWizard key and no view.user opens an empty dialog silently. Grant it at /admin/crm/role.

There genuinely are no active users. The lightweight list behind Select all returns active accounts only.

Every recipient failed

Read the error on a failed recipient card — the send job records the mail transport's own message there, along with the attempt count.

535, "Username and Password not accepted", "Invalid login". The transport credentials in .env are wrong or the provider has revoked them. Gmail and Outlook both require an app password, not the account password.

Verify by triggering any transactional email from the platform — a password reset to your own address. If that fails too, the problem is platform-wide, not MailWizard.

Almost always a port and encryption mismatch. The client treats the connection as secure when the port is 465 or APP_NODEMAILER_SMTP_ENCRYPTION is ssl — and ssl is the default. So leaving the encryption unset while using port 587 negotiates SSL against a STARTTLS port. Pair 587 with tls and 465 with ssl.

421, 454 4.7.0 Too many login attempts, "rate limit exceeded". Your provider is refusing the volume. Lower Emails per hour and retry the failures later.

Note that the throttle is per campaign: three campaigns at 100 each are 300 emails an hour against one account.

A 500 with this message means APP_EMAILER holds a value that is not one of local, nodemailer-service, nodemailer-smtp or nodemailer-sendgrid. Note that deleting the variable entirely does not fall back to what .env.example ships — the code's own default is nodemailer-service.

That is the circuit breaker working. Five consecutive failures are treated as a provider outage rather than five bad addresses, so sending stops for the rest of the run and the untouched recipients stay PENDING. Fix the transport; the next hourly run resumes.

Recipients received a blank email

The template body is empty. The Templates list flags this with a No content badge on the row.

If the template was created with the visual editor on a build before v6.1.0, the create flow discarded the design and stored a literal {} while reporting success. Editing always saved correctly, so opening the template and saving it once repairs it. Check every template you created that way after upgrading.

Recipients received the email twice

Two causes, both operator actions.

Stop was used instead of Pause. Stop resets every recipient to PENDING, so restarting emails everybody again. The interface confirms first and names how many people that is. Use Pause to halt a send, and Retry failed to pick up only the failures.

A running campaign was saved from the campaign page. That page posts the whole recipient list back as it was when the page loaded, overwriting anything the send job has written since. Recipients already delivered to revert to PENDING and are emailed again on the next run. Pause the campaign, reload the page, edit, then start it.

The template editor has no Blocks panel

Three possibilities:

  • You have no saved blocks. The panel is hidden rather than shown empty, on purpose. Save one block and it appears next time.
  • The block you just saved is not there yet. The block list is read once when the editor initialises. The success toast offers a Reload editor action that re-initialises with the new block and carries your current design across.
  • The role lacks view.mailwizard.block. No panel, no explanation. Grant it alongside the template permissions.

Opening a template shows a blank canvas

The stored design is not something the editor can read — usually because the template was imported as raw HTML. The Templates list badges this as HTML only.

The template still sends correctly; it simply cannot be edited visually. Treat it as read-only and re-import the whole thing when it needs to change.

A rename did not stick

Template names are write-once. The editor's name field is editable and posts the value, but the update endpoint writes the body and design only. There is no other rename path. Create a new template with the right name and repoint the campaigns that use it.

Campaign names can be changed normally, through the campaign page.

Emails are arriving in spam

Nothing in MailWizard influences this. The checks worth running, in order:

    • SPF, DKIM and DMARC published for the domain in your From address
    • DKIM configured at the provider — the APP_NODEMAILER_DKIM_* variables only apply to the local sendmail transport
    • A sending volume your domain's reputation supports; a new domain emitting a thousand messages in an hour looks compromised
    • An unsubscribe link in the template — nothing adds one for you
    • Images hosted on your own domain rather than inlined as base64
    • Addresses that actually exist; repeated delivery to dead mailboxes is a strong negative signal

Remember the reporting ceiling: SENT means your mail transport accepted the message. It does not mean it was delivered, and it certainly does not mean it reached an inbox. There is no open or click tracking in this product, so inbox placement can only be measured from your provider's dashboard or by seeding test addresses.

Staging sent real email to real customers

MAIL_DISABLED=true stops the platform's queued and templated email. It does not stop MailWizard, whose send job calls the mailer directly and never consults that flag.

Before restoring a production database onto any non-production box, do one of:

  • Disable the mailwizard extension at /admin/system/extension, or
  • Set every campaign to PENDING or CANCELLED, or
  • Point APP_EMAILER at a transport that cannot reach the internet.

Where to look next

Symptom Page
Nothing sends, cron suspected Processes and ports
Mail fails platform-wide Core troubleshooting
Transport variables Environment variables
Permissions and roles Roles and permissions
How the send loop behaves How sending works