My app's email did not arrive
When the app says it sent an email and it never shows up, the panel shows what the mail server saw. Open the project, Sends tab (and Email for the connection test). For all projects at once use Email → Sends → Outgoing.
1. Check the app’s last attempt
Section titled “1. Check the app’s last attempt”On the project’s Sends tab, Last connection attempt from the app shows when the app last talked to the mail server and whether it was accepted or refused. Never seen means the mail server logged no attempt at all: the app is not reaching it (wrong variables, email turned off, project not restarted).
2. Refused attempts
Section titled “2. Refused attempts”The Refused attempts section lists what the server refused before accepting a message: wrong password, a temporary ban for too many attempts, TLS failure, sender not allowed, sending limit. Each row shows the time, the reason and the login used. Only attempts coming from the internal network (the project’s app or the panel itself) with the project mailbox login appear on the project: wrong passwords that came from the internet, from bots, are never blamed on the app. They show up on the global E-mail > Envios > Saídas page, in a separate list called External attempts. The “Test connection from the app” button does not count as an app attempt. TLS refusals carry no login and appear only on the global page.
Click the date of an attempt to open its details: reason, what to do, login, project, origin (internal network or internet) and the submission listener that refused it. Because the attempt was refused before the message entered the queue, there is no recipient or delivery response: those exist only for accepted sends, in the sends section above. Attempts are kept for 30 days (up to 300 a day per project, and one per minute for the same reason and login); the list shows the 50 most recent and counts the total. If saving fails, the attempt is saved again on the next round (up to 5 rounds; then the panel gives up and logs it). If the panel cannot read the sending mailboxes, it uses the last list it read to tie the attempt to a project; with no list at all, the attempt is kept without a project. The “Test connection from the app” button is recognised only while the panel stays up: after a restart, a refusal caused by the test may show up as an app attempt.
| Reason | What to do |
|---|---|
| Username or password refused | The password the app uses does not match the mailbox on the server. In E-mail, use Sync with the mail server (or reset the mailbox password) and restart the project. Also check MAIL_USERNAME and MAIL_PASSWORD (or link them to the panel’s email, below). |
| TLS connection did not complete | The app does not trust the mail server certificate, or uses an old TLS version. Use host mail.<your domain> on port 587 with STARTTLS. |
| Sender not allowed | The MAIL_FROM_ADDRESS address does not belong to the project’s mailbox. Use the mailbox address. |
| Not authenticated | The app tried to send without a username and password. |
3. Why nothing arrived?
Section titled “3. Why nothing arrived?”With no sends in the last 24 hours, the Sends tab shows the Why nothing arrived? card with whatever applies to the project:
- the project’s email is off, or the mailbox has no password;
- the test inbox is on: the messages are there, they were not delivered;
- email was turned on or changed but the project was not redeployed;
MAIL_MAILERislogorarray: Laravel only writes the email to a file or discards it;MAIL_HOST,MAIL_USERNAMEorMAIL_PASSWORDare not linked to the panel’s SMTP (in Email → Link variables, link them toSMTP_HOST,SMTP_USERandSMTP_PASS);- the queue without a worker (item 5);
- the server refused recent attempts (item 2).
4. Test the connection from the app
Section titled “4. Test the connection from the app”On the project’s Email tab, Test connection from the app follows the same path as the app: it connects
to mail.<your domain>:587, runs STARTTLS with certificate verification and logs in with the project’s
mailbox. It sends no message and never shows the password. It stops at the first failing step and explains why.
The test runs in the panel itself, which sits on the same Docker network as the projects; a network rule that
exists only inside the app’s container is not covered.
5. Laravel: queue without a worker
Section titled “5. Laravel: queue without a worker”If QUEUE_CONNECTION is not sync (for example database or redis; the Laravel 11 default is database)
and no process runs queue:work, queue:listen or horizon, the panel warns We could not
find a queue worker — queued e-mails and jobs may stay stuck. The search is static (compose files, Dockerfiles,
supervisor configs and scripts, including subfolders such as docker/ and scripts/, and the values set in
environment:, env_file and Dockerfile ENV), so a worker started some other way is not seen. Without a worker
the emails sit in the jobs table. Two fixes:
- Set
QUEUE_CONNECTION=syncin the project Variables (sends during the request: simplest, slower for the user). - Add a worker service to
docker-compose.yml:
services: worker: build: . command: php artisan queue:work --sleep=3 --tries=3 --max-time=3600 restart: unless-stopped depends_on: - appUse the same image and variables as the app service. Containers get the project variables on the next deploy.
6. Laravel: LOG_CHANNEL=stderr
Section titled “6. Laravel: LOG_CHANNEL=stderr”By default Laravel writes errors to storage/logs/laravel.log inside the container, and the project’s Logs
tab cannot see them. Set LOG_CHANNEL=stderr in the Variables and exceptions show up in the Logs tab. This is
only a suggestion, not an error.
Server logs
Section titled “Server logs”If the problem looks like the mail server or the proxy, see Server logs.