Summary
Transactional email is configured inconsistently: the app is using Django SMTP delivery, but the environment/config suggests a partial Twilio SendGrid setup that does not match the code path.
Findings
-
The app is using SMTP, not the SendGrid API client.
progress_rpg/settings/prod.py sets EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend".
- There are no active
sendgrid client imports/usages in the email send path.
-
The configured credential name does not match the backend in use.
- Django SMTP reads
EMAIL_HOST_PASSWORD from progress_rpg/settings/base.py.
- The local env has a
SENDGRID_API_KEY entry, but no EMAIL_HOST_PASSWORD entry.
- Result: SMTP auth will fail even if a SendGrid API key exists, because the SMTP backend never reads
SENDGRID_API_KEY.
-
The SMTP host value is malformed.
- The local env's
EMAIL_HOST value has leading whitespace.
- Result: hostname resolution / SMTP connection can fail before auth.
-
The built-in email smoke-test command is broken.
users/management/commands/send_test_email.py references an undefined recipient variable after calling send_mail(...).
- Result: manual verification is misleading because the command crashes even if the send succeeds.
-
Some auth emails are sent asynchronously through Celery.
users/adapters.py queues confirmation emails through send_rendered_email_task.delay(...).
- Result: even with correct SMTP config, signup/confirmation mail also depends on the Celery worker having the same valid email env vars and being healthy.
Why this breaks in practice
- Signup requires email verification (
ACCOUNT_EMAIL_VERIFICATION = "mandatory"), so if transactional email fails, users cannot complete registration.
- The current setup mixes SendGrid package presence / API-key naming with an SMTP backend, so the key config is effectively disconnected from the code that actually sends mail.
Recommended fix
Choose one delivery path and wire it consistently.
Option A: Keep SMTP (smallest change)
- Set
EMAIL_HOST=smtp.sendgrid.net with no leading/trailing whitespace.
- Set
EMAIL_PORT=587.
- Set
EMAIL_HOST_USER=apikey.
- Set
EMAIL_HOST_PASSWORD to the SendGrid API key.
- Keep
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend.
- Set
DEFAULT_FROM_EMAIL / sender address to a verified sender or authenticated domain in SendGrid.
- Ensure the same env vars are present for both the web service and Celery worker.
- Fix the
send_test_email command so it reports success correctly.
Option B: Switch to the SendGrid API backend
- Replace SMTP backend usage with a real SendGrid backend/client integration.
- Use
SENDGRID_API_KEY directly in settings.
- Remove unused/confusing SMTP-only env expectations.
Acceptance criteria
- Transactional emails send successfully in the target environment.
- Signup confirmation emails are delivered end-to-end.
- Web and Celery use the same valid email configuration.
- The smoke-test command provides a trustworthy pass/fail result.
- Email configuration is documented so the chosen delivery path is unambiguous.
Summary
Transactional email is configured inconsistently: the app is using Django SMTP delivery, but the environment/config suggests a partial Twilio SendGrid setup that does not match the code path.
Findings
The app is using SMTP, not the SendGrid API client.
progress_rpg/settings/prod.pysetsEMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend".sendgridclient imports/usages in the email send path.The configured credential name does not match the backend in use.
EMAIL_HOST_PASSWORDfromprogress_rpg/settings/base.py.SENDGRID_API_KEYentry, but noEMAIL_HOST_PASSWORDentry.SENDGRID_API_KEY.The SMTP host value is malformed.
EMAIL_HOSTvalue has leading whitespace.The built-in email smoke-test command is broken.
users/management/commands/send_test_email.pyreferences an undefinedrecipientvariable after callingsend_mail(...).Some auth emails are sent asynchronously through Celery.
users/adapters.pyqueues confirmation emails throughsend_rendered_email_task.delay(...).Why this breaks in practice
ACCOUNT_EMAIL_VERIFICATION = "mandatory"), so if transactional email fails, users cannot complete registration.Recommended fix
Choose one delivery path and wire it consistently.
Option A: Keep SMTP (smallest change)
EMAIL_HOST=smtp.sendgrid.netwith no leading/trailing whitespace.EMAIL_PORT=587.EMAIL_HOST_USER=apikey.EMAIL_HOST_PASSWORDto the SendGrid API key.EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend.DEFAULT_FROM_EMAIL/ sender address to a verified sender or authenticated domain in SendGrid.send_test_emailcommand so it reports success correctly.Option B: Switch to the SendGrid API backend
SENDGRID_API_KEYdirectly in settings.Acceptance criteria