🔧(project) add DJANGO_EMAIL_URL_APP environment variable

Share invitation emails embedded `Site.domain` directly, producing
schemeless links that mail clients failed to resolve. Introduce a
`DJANGO_EMAIL_URL_APP` environment variable holding the app's
absolute URL used when building invitation links, with a fallback
on the current Site domain when unset. Wire it in dev env, helm
dev values, the helm example and the env reference.
This commit is contained in:
Nathan Panchout
2026-04-20 15:12:26 +02:00
parent af8ba1031f
commit 3731033f5b
8 changed files with 39 additions and 4 deletions

View File

@@ -15,6 +15,7 @@ and this project adheres to
- ✨(frontend) add ErrorIcon component and support numeric icon sizes
- ✨(frontend) make file upload abortable in driver layer
- ✨(frontend) files preview v2
- 🔧(project) add DJANGO_EMAIL_URL_APP environment variable
### Fixed

View File

@@ -50,6 +50,7 @@ This document lists all configurable environment variables for the Drive applica
| `EMAIL_HOST_USER` | SMTP username for email sending | `None` |
| `EMAIL_LOGO_IMG` | Logo image URL for email templates | `None` |
| `EMAIL_PORT` | SMTP port for email sending | `None` |
| `EMAIL_URL_APP` | URL used in emails to link back to the app | `None` |
| `EMAIL_USE_SSL` | Use SSL for SMTP connection | `False` |
| `EMAIL_USE_TLS` | Use TLS for SMTP connection | `False` |
| `FEATURES_ALPHA` | Enable alpha features | `False` |

View File

@@ -24,6 +24,7 @@ backend:
DJANGO_EMAIL_HOST: "mailcatcher"
DJANGO_EMAIL_LOGO_IMG: https://drive.127.0.0.1.nip.io/assets/logo-suite-numerique.png
DJANGO_EMAIL_PORT: 1025
DJANGO_EMAIL_URL_APP: https://drive.127.0.0.1.nip.io
DJANGO_EMAIL_USE_SSL: False
LOGGING_LEVEL_LOGGERS_ROOT: INFO
LOGGING_LEVEL_LOGGERS_APP: INFO

View File

@@ -20,6 +20,7 @@ DJANGO_EMAIL_BRAND_NAME="La Suite Numérique"
DJANGO_EMAIL_HOST="mailcatcher"
DJANGO_EMAIL_LOGO_IMG="http://localhost:3000/assets/logo-suite-numerique.png"
DJANGO_EMAIL_PORT=1025
DJANGO_EMAIL_URL_APP="http://localhost:3000"
# Media
STORAGES_STATICFILES_BACKEND=django.contrib.staticfiles.storage.StaticFilesStorage

View File

@@ -915,17 +915,17 @@ class Item(TreeModel, BaseModel):
return
context = context or {}
domain = Site.objects.get_current().domain
base_url = settings.EMAIL_URL_APP or Site.objects.get_current().domain
language = language or get_language()
context.update(
{
"brandname": settings.EMAIL_BRAND_NAME,
"item": self,
"domain": domain,
"domain": base_url,
"link": (
f"{domain}/explorer/items/files/{self.id}/"
f"{base_url}/explorer/items/files/{self.id}/"
if self.type == ItemTypeChoices.FILE
else f"{domain}/explorer/items/{self.id}/"
else f"{base_url}/explorer/items/{self.id}/"
),
"logo_img": settings.EMAIL_LOGO_IMG,
}

View File

@@ -847,6 +847,35 @@ def test_models_items__email_invitation__link_for_file():
assert f"/explorer/items/{item.id}/" not in email.body
@pytest.mark.parametrize(
"email_url_app",
[
"https://test-example.com", # Test with EMAIL_URL_APP set
None, # Test fallback to Site domain
],
)
def test_models_items__email_invitation__url_app_param(email_url_app, settings):
"""
Email invitation uses EMAIL_URL_APP when set, or falls back to the Site domain.
"""
settings.EMAIL_URL_APP = email_url_app
item = factories.ItemFactory(type=models.ItemTypeChoices.FOLDER)
sender = factories.UserFactory()
item.send_invitation_email("guest@example.com", models.RoleChoices.EDITOR, sender, "en")
# pylint: disable-next=no-member
email = mail.outbox[-1]
email_content = " ".join(email.body.split())
if email_url_app:
assert f"https://test-example.com/explorer/items/{item.id}/" in email_content
else:
# Default Site domain is example.com
assert f"example.com/explorer/items/{item.id}/" in email_content
@mock.patch(
"core.models.send_mail",
side_effect=smtplib.SMTPException("Error SMTPException"),

View File

@@ -1000,6 +1000,7 @@ class Base(Configuration):
EMAIL_HOST_PASSWORD = SecretFileValue(None)
EMAIL_LOGO_IMG = values.Value(None)
EMAIL_PORT = values.PositiveIntegerValue(None)
EMAIL_URL_APP = values.Value(None)
EMAIL_USE_TLS = values.BooleanValue(False)
EMAIL_USE_SSL = values.BooleanValue(False)
EMAIL_FROM = values.Value("from@example.com")

View File

@@ -24,6 +24,7 @@ backend:
DJANGO_EMAIL_HOST: "mailcatcher"
DJANGO_EMAIL_LOGO_IMG: https://drive.127.0.0.1.nip.io/assets/logo-suite-numerique.png
DJANGO_EMAIL_PORT: 1025
DJANGO_EMAIL_URL_APP: https://drive.127.0.0.1.nip.io
DJANGO_EMAIL_USE_SSL: False
LOGGING_LEVEL_LOGGERS_ROOT: INFO
LOGGING_LEVEL_LOGGERS_APP: INFO