Saltar a contenido

Email Delivery Log

Available to: Platform Admin (Django admin)

Every outbound transactional email — tenant invites, workflow notifications, and platform alerts — is recorded in the Email log (EmailLog model). Use it to confirm whether an email was sent, skipped, or failed, and why.


Where to view the log

  1. Sign in to Django admin at https://<your-api-host>/django-admin/ using a platform admin email and a Django password set via python manage.py set_django_admin_password <email> on the web service (Auth0 login does not apply here). See Platform Admin.
  2. Open Companies → Email logs.
  3. Filter by status, category, or template name, or search by recipient address or Mailgun message ID.

The log is read-only. Rows are created automatically by the Celery worker when send_transactional_email runs.


What gets logged

Category Examples
invite Welcome email when a team member is invited to a tenant
workflow_notification Bid submitted, bid became job, invoice created, payment recorded, etc.
platform_alert New access-request alert to platform admins
other Access-request confirmation, access-granted, and other one-off sends

Each row stores: recipients, subject, template name, status, Mailgun message ID (when sent), HTTP status, error detail, and timestamp.


Status values

Status Meaning
sent Mailgun accepted the message. Check provider_message_id in the Mailgun dashboard if the recipient did not receive it (spam, sandbox restrictions, etc.).
failed Mailgun returned an error or the HTTP request failed. See http_status and error_detail.
skipped_no_config MAILGUN_API_KEY or MAILGUN_DOMAIN is not set on the Celery worker. The send was never attempted.
skipped_cap Daily send cap (~100) was reached.
skipped_no_recipients No valid recipient addresses were provided.
render_failed Email template could not be rendered (configuration or template bug).

Diagnosing missing emails

Work through these checks in order:

1. Is there an EmailLog row for the event?

  • No row at all — the Celery task was never executed. Confirm the worker component is running in App Platform and connected to Redis. Workflow notifications and invites use .delay(); they do not send inline from the web process.
  • Row with skipped_no_config — set MAILGUN_API_KEY, MAILGUN_DOMAIN, and DEFAULT_FROM_EMAIL on the worker (and web for consistency). Without these, sends are skipped silently except for this log entry.
  • Row with skipped_cap — wait until the next UTC day or raise the cap only after upgrading Mailgun.
  • Row with failed — inspect http_status: 401/403 usually means a bad API key; 4xx on a sandbox domain often means the recipient is not authorized in Mailgun.

2. Tenant invite-specific checks

Invite welcome emails are only queued after Auth0 provisioning succeeds. If Auth0 invite fails, see the tenant Activity log (AUTH0_INVITE_FAILED) on the user record — no welcome email is sent.

Required env vars on web (invite is triggered from the API):

  • AUTH0_MGMT_CLIENT_ID
  • AUTH0_MGMT_CLIENT_SECRET
  • AUTH0_INVITE_ENABLED=True (default)

3. Workflow notification-specific checks

Notifications respect Settings → Email notifications per tenant. If the event is disabled or no roles are selected, _dispatch_tenant_event returns without calling Mailgun — no EmailLog row is created for that case.

Trigger a test event (e.g. submit a bid for approval) and then refresh the Email log.

4. Mailgun sandbox vs production domain

Sandbox domains only deliver to authorized recipients in the Mailgun dashboard. For production, verify a custom sending domain (e.g. mg.hardhatflow.com) and set MAILGUN_DOMAIN and DEFAULT_FROM_EMAIL to match.

5. Sent but not received

If status is sent and provider_message_id is populated, delivery left Hardhat Flow successfully. Use the Mailgun Logs or Suppressions UI with that message ID to trace bounces, spam filtering, or blocks.


Required production environment variables

Set these on web and worker in App Platform (worker is required for all .delay() sends):

Variable Purpose
MAILGUN_API_KEY Mailgun private API key
MAILGUN_DOMAIN Verified sending domain
DEFAULT_FROM_EMAIL From address matching the Mailgun domain
FRONTEND_URL Links in email bodies (e.g. bid/invoice detail URLs)

For tenant invites, also on web:

Variable Purpose
AUTH0_MGMT_CLIENT_ID Auth0 Management API (M2M)
AUTH0_MGMT_CLIENT_SECRET Auth0 Management API secret
AUTH0_SPA_CLIENT_ID Password-change ticket for invite links

See Environment Variables for the full catalog, Mailgun operator checklist, and per-component requirements. See also Deployment.