NetSendo

How-to · Sending and deliverability

Troubleshoot emails that NetSendo does not send

Find why NetSendo isn't sending: check the queue and scheduler containers, the CRON schedule, the campaign's queue status, mailbox errors, Mailpit and logs.

For NetSendo 2.7.0, checked against its source code on 2026-11-08.

In short

Campaigns and autoresponders need two background services: the scheduler runs cron:process-queue every minute and the queue worker sends each email through a mailbox. Check docker compose ps, the campaign's Queue Progress (Planned, Queued, Sent, Failed), the error of failed recipients and storage/logs/laravel.log, fix the cause, then click Retry. Mail that ends up in Mailpit went through the MAIL_* settings in .env, not through a mailbox.

Before you start

  • A shell on the Docker host, in the folder with docker-compose.yml. The commands use its service names: app, queue, scheduler, mailpit.
  • The campaign that did not go out.
  • How sending works. The scheduler service runs php artisan schedule:work, which starts cron:process-queue every minute. That command moves due recipients from Planned to Queued and puts one job per email on the queue. The queue service (php artisan queue:work --queue=default,notifications) sends each email through a mailbox and marks it Sent or Failed. Test Connection and Send test skip both services.

Steps

  1. Run docker compose ps and check that queue and scheduler are running.
  2. In NetSendo, open Address List → Email Message List and click the Statistics icon of the campaign.
  3. Read Queue Progress: Planned, Queued, Sent, Failed and Skipped.
  4. In the recipients list, click a failed recipient's error to see the full text.
  5. Check the scheduler with docker compose logs --tail=50 scheduler and docker compose exec app php artisan schedule:list; cron:process-queue must be listed for every minute.
  6. Check whether sending is allowed right now: docker compose exec app php artisan cron:process-queue --dry-run -v. It sends nothing.
  7. Check the queue worker with docker compose logs --tail=100 queue.
  8. Read the application log under Help & Resources → System Logs, tab Laravel Logs, or run docker compose exec app tail -n 200 storage/logs/laravel.log.
  9. List jobs the worker gave up on: docker compose exec app php artisan queue:failed.
  10. Fix the cause with the sections below.
  11. On the campaign's Statistics page, click Retry under Failed.

Check that it works

  • On the Statistics page, Sent grows while Planned and Queued shrink.
  • storage/logs/laravel.log gets a line Email sent via smtp (<mailbox name>) to <address> for each email.
  • Settings → CRON Settings, tab Execution History, shows a new run every minute.

If it doesn't work

Planned stays, nothing is queued

The scheduler is not running or sending is outside the allowed hours.

  • Start it with docker compose up -d scheduler. After an update, queue and scheduler start only when app is healthy and then wait for its migrations ("Waiting for the database schema"), for up to 1,800 seconds. Follow docker compose logs -f app.
  • Until the scheduler has run its queue jobs once, the panel shows "⚠️ CRON is not configured! Scheduled messages will not be sent automatically."
  • If the dry run prints ⏸️ Wysyłka jest obecnie wstrzymana wg harmonogramu globalnego (2.7.0 prints this command's output in Polish: "dispatch is paused by the global schedule"), open Settings → CRON Settings, tab Global Settings, and check Weekly schedule for days set to Dispatch disabled or a narrow From/To window. The hours are UTC, the application's time zone. A list can have its own window: Edit the list, Settings tab, Schedule (CRON). With -v the dry run lists the lists allowed right now.
  • The message must be scheduled for now or earlier, and an autoresponder must be active.
  • Without Docker, add the cron entry from the Installation Instructions tab: * * * * * cd /path-to-netsendo && php artisan schedule:run >> /dev/null 2>&1.
  • NETSENDO_DORMANT=true in .env stops all scheduled work.

Queued grows, Sent does not

The queue worker is down. Run docker compose up -d queue (or docker compose restart queue) and read its log. Entries stuck in Queued for more than 30 minutes go back to Planned and are sent by the next run. The worker must read both queues, --queue=default,notifications; docker-compose.yml files from 2.1.3 and older lack that (configuration docs).

Recipients are Failed

Read the error and fix its cause:

  • Brak skonfigurowanej skrzynki pocztowej… (Polish in 2.7.0): there is no active mailbox. Add one under Settings → Mailboxes, for example Amazon SES.
  • Żadna aktywna skrzynka pocztowa nie ma włączonego typu wysyłki "broadcast"…: no active mailbox may send this message type, or the mailbox has reached its Daily Sending Limit. Tick the type under Allowed Message Types or raise the limit.
  • An SMTP reply such as 535 (login) or 554 (rejected): fix the mailbox and click Test Connection on its card.
  • Throttling and other temporary 4xx replies are retried, up to 3 attempts with growing delays, before the recipient fails. Lower Message limit / minute under Settings → CRON Settings (default 100).
  • Job failed permanently: …: the worker gave up on the job; the rest of the text names the cause.

Retry sets every failed recipient back to Planned, so the next run sends them real emails.

Tests arrive, the campaign does not

Test Connection and Send test send directly, without the queue and the scheduler. If they work, the mailbox is fine: check the two services and the schedule above. Also check which mailbox the campaign uses: the message's Sending mailbox, else the list's Default Outbound Mailbox (SMTP), else the default mailbox.

Emails land in Mailpit

Mailpit catches everything sent through the MAIL_* settings in .env, which default to MAIL_HOST=mailpit and port 1025. Its inbox is at http://localhost:5031, bound to 127.0.0.1; from your own computer use an SSH tunnel such as ssh -L 5031:127.0.0.1:5031 you@your-server.

Through MAIL_* go team invitations, export-ready notices, task reminders, and a list's system emails, such as signup confirmations, when no active mailbox has System ticked. Campaigns and autoresponders never do. Tick System on a mailbox, point MAIL_* at a real SMTP server, or both, then run docker compose up -d --force-recreate (environment variables).

Do it with an AI assistant

The NetSendo MCP server can read a campaign's delivery status with get_campaign_stats, show a list's sending window with get_list_cron_settings, list mailboxes and their allowed types with list_mailboxes, send a test with send_campaign_test and re-queue failed recipients with resend_campaign_failed (it reports the count first and needs confirm=true). It cannot read container logs. Setup: MCP docs.

Campaign 42 in NetSendo has not gone out. Show its delivery stats, check whether its list may send right now and which mailbox it uses, and tell me how many recipients failed before you retry them.

Something different in your panel? Your instance may run another release; see the release notes or write to support@netsendo.com. Every page of these docs is also available as Markdown for AI assistants: request https://netsendo.com/en/docs/how-to/emails-not-sending with Accept: text/markdown.