diff --git a/dandiapi/api/mail.py b/dandiapi/api/mail.py
index 4d94dfcfb..63d5192f4 100644
--- a/dandiapi/api/mail.py
+++ b/dandiapi/api/mail.py
@@ -43,8 +43,17 @@ def user_greeting_name(user: User, socialaccount: SocialAccount = None) -> str:
return social_user['username']
-def build_message(subject: str, message: str, to: list[str], html_message: str | None = None):
- email_message = mail.EmailMultiAlternatives(subject=subject, body=message, to=to)
+def build_message( # noqa: PLR0913
+ to: list[str],
+ subject: str,
+ message: str,
+ html_message: str | None = None,
+ cc: list[str] | None = None,
+ bcc: list[str] | None = None,
+):
+ email_message = mail.EmailMultiAlternatives(
+ subject=subject, body=message, to=to, cc=cc, bcc=bcc
+ )
if html_message is not None:
email_message.attach_alternative(html_message, 'text/html')
return email_message
@@ -206,3 +215,29 @@ def send_dandiset_unembargoed_message(dandiset: Dandiset):
messages = [build_dandiset_unembargoed_message(dandiset)]
with mail.get_connection() as connection:
connection.send_messages(messages)
+
+
+def build_dandiset_unembargo_failed_message(dandiset: Dandiset):
+ dandiset_context = {
+ 'identifier': dandiset.identifier,
+ }
+
+ render_context = {**BASE_RENDER_CONTEXT, 'dandiset': dandiset_context}
+ html_message = render_to_string('api/mail/dandiset_unembargo_failed.html', render_context)
+ return build_message(
+ subject=f'DANDI: Unembargo failed for dandiset {dandiset.identifier}',
+ message=strip_tags(html_message),
+ html_message=html_message,
+ to=[owner.email for owner in dandiset.owners],
+ bcc=[settings.DANDI_DEV_EMAIL],
+ )
+
+
+def send_dandiset_unembargo_failed_message(dandiset: Dandiset):
+ logger.info(
+ 'Sending dandiset unembargo failed message for dandiset %s to dandiset owners and devs',
+ dandiset.identifier,
+ )
+ messages = [build_dandiset_unembargo_failed_message(dandiset)]
+ with mail.get_connection() as connection:
+ connection.send_messages(messages)
diff --git a/dandiapi/api/tasks/__init__.py b/dandiapi/api/tasks/__init__.py
index 2a7fa9318..98b919604 100644
--- a/dandiapi/api/tasks/__init__.py
+++ b/dandiapi/api/tasks/__init__.py
@@ -4,6 +4,7 @@
from celery.utils.log import get_task_logger
from dandiapi.api.doi import delete_doi
+from dandiapi.api.mail import send_dandiset_unembargo_failed_message
from dandiapi.api.manifests import (
write_assets_jsonld,
write_assets_yaml,
@@ -82,4 +83,10 @@ def unembargo_dandiset_task(dandiset_id: int):
from dandiapi.api.services.embargo import unembargo_dandiset
ds = Dandiset.objects.get(pk=dandiset_id)
- unembargo_dandiset(ds)
+
+ # If the unembargo fails for any reason, send an email, but continue the error propagation
+ try:
+ unembargo_dandiset(ds)
+ except Exception:
+ send_dandiset_unembargo_failed_message(ds)
+ raise
diff --git a/dandiapi/api/templates/api/mail/dandiset_unembargo_failed.html b/dandiapi/api/templates/api/mail/dandiset_unembargo_failed.html
new file mode 100644
index 000000000..176a49476
--- /dev/null
+++ b/dandiapi/api/templates/api/mail/dandiset_unembargo_failed.html
@@ -0,0 +1,6 @@
+There was an error during the unembargo of dandiset
+{{dandiset.identifier }}. This has been reported to the developers, and will be
+investigated as soon as possible. We hope to have this resolved soon! Please avoid making any major changes to this
+dandiset in the meantime, as that may hinder or delay the process of resolving this issue.
+
+You are receiving this email because you are an owner of this dandiset.
\ No newline at end of file
diff --git a/dandiapi/api/tests/test_unembargo.py b/dandiapi/api/tests/test_unembargo.py
index f59d9fc59..9740ecebf 100644
--- a/dandiapi/api/tests/test_unembargo.py
+++ b/dandiapi/api/tests/test_unembargo.py
@@ -14,6 +14,7 @@
)
from dandiapi.api.services.embargo.exceptions import DandisetActiveUploadsError
from dandiapi.api.services.exceptions import DandiError
+from dandiapi.api.tasks import unembargo_dandiset_task
if TYPE_CHECKING:
from dandiapi.api.models.asset import AssetBlob
@@ -162,3 +163,19 @@ def test_unembargo_dandiset(
owner_email_set = {user.email for user in owners}
mailoutbox_to_email_set = set(mailoutbox[0].to)
assert owner_email_set == mailoutbox_to_email_set
+
+
+@pytest.mark.django_db()
+def test_unembargo_dandiset_task_failure(draft_version_factory, mailoutbox):
+ # Intentionally set the status to embargoed so the task will fail
+ draft_version = draft_version_factory(dandiset__embargo_status=Dandiset.EmbargoStatus.EMBARGOED)
+ ds: Dandiset = draft_version.dandiset
+
+ with pytest.raises(DandiError):
+ unembargo_dandiset_task.delay(ds.pk)
+
+ assert mailoutbox
+ assert 'Unembargo failed' in mailoutbox[0].subject
+ payload = mailoutbox[0].message().get_payload()[0].get_payload()
+ assert ds.identifier in payload
+ assert 'error during the unembargo' in payload