diff --git a/arkindex/documents/export/__init__.py b/arkindex/documents/export/__init__.py
index b3c120d751ac360c3cc362032e4e4adcbc961bd7..950be0edc717817427a42b3bce80c16afd68ca95 100644
--- a/arkindex/documents/export/__init__.py
+++ b/arkindex/documents/export/__init__.py
@@ -7,7 +7,10 @@ import uuid
 from datetime import datetime, timezone
 from pathlib import Path
 
+from django.conf import settings
+from django.core.mail import send_mail
 from django.db import connections
+from django.template.loader import render_to_string
 from django.utils.text import slugify
 from django_rq import job
 from rq import get_current_job
@@ -79,6 +82,23 @@ def save_sqlite(rows, table, cursor):
     cursor.executemany(query, rows)
 
 
+def send_email(subject, template_name, corpus_export, **context):
+    context['corpus_export'] = corpus_export
+    context['hostname'] = settings.PUBLIC_HOSTNAME
+    sent = send_mail(
+        subject=subject,
+        message=render_to_string(
+            template_name,
+            context=context,
+        ),
+        from_email=None,
+        recipient_list=[corpus_export.user.email],
+        fail_silently=True,
+    )
+    if sent == 0:
+        logger.error(f'Failed to send email to {corpus_export.user.email}')
+
+
 @job('high')
 def export_corpus(corpus_export: CorpusExport) -> None:
     _, db_path = tempfile.mkstemp(suffix='db')
@@ -135,9 +155,21 @@ def export_corpus(corpus_export: CorpusExport) -> None:
 
         corpus_export.state = CorpusExportState.Done
         corpus_export.save()
-    except Exception:
+
+        send_email(
+            'Arkindex project export completed',
+            'export_success.html',
+            corpus_export,
+        )
+    except Exception as e:
         corpus_export.state = CorpusExportState.Failed
         corpus_export.save()
+        send_email(
+            'Arkindex project export failed',
+            'export_error.html',
+            corpus_export,
+            error=e.args[0],
+        )
         raise
     finally:
         os.unlink(db_path)
diff --git a/arkindex/documents/tests/tasks/test_export.py b/arkindex/documents/tests/tasks/test_export.py
index e5b66023b3318aa7df7309a641e2f5515abbf678..8238a0314fa70580ecc1ca1cffff461bcba00462 100644
--- a/arkindex/documents/tests/tasks/test_export.py
+++ b/arkindex/documents/tests/tasks/test_export.py
@@ -2,8 +2,12 @@ import json
 import os
 import sqlite3
 from datetime import datetime, timezone
+from textwrap import dedent
 from unittest.mock import call, patch
 
+from django.core import mail
+from django.test import override_settings
+
 from arkindex.dataimport.models import WorkerVersion
 from arkindex.documents.export import export_corpus
 from arkindex.documents.models import (
@@ -22,6 +26,7 @@ from arkindex.project.tests import FixtureTestCase
 
 class TestExport(FixtureTestCase):
 
+    @override_settings(PUBLIC_HOSTNAME='https://darkindex.lol')
     @patch('arkindex.documents.export.datetime')
     @patch('arkindex.documents.export.os.unlink')
     @patch('arkindex.project.aws.s3.Object')
@@ -276,3 +281,49 @@ class TestExport(FixtureTestCase):
         )
 
         os.unlink(db_path)
+
+        # Download URL is sent by email
+        self.assertEqual(len(mail.outbox), 1)
+        message = mail.outbox[0]
+        self.assertEqual(message.subject, 'Arkindex project export completed')
+        self.assertListEqual(message.to, [self.user.email])
+        self.assertEqual(message.body, dedent(f"""
+        Hello Test user,
+
+        Your export for the Unit Tests project is completed.
+
+        You can download it at:
+        https://darkindex.lol/api/v1/export/{export.id}/
+
+        --
+        Arkindex
+
+        """))
+
+    @patch('arkindex.project.aws.s3.Object')
+    def test_export_fail(self, s3_object_mock):
+        s3_object_mock.return_value.upload_file.side_effect = ZeroDivisionError('i ran out of elbow oil')
+
+        export = self.corpus.exports.create(user=self.user)
+        with self.assertRaises(ZeroDivisionError):
+            export_corpus(export)
+
+        export.refresh_from_db()
+        self.assertEqual(export.state, CorpusExportState.Failed)
+        self.assertEqual(len(mail.outbox), 1)
+        message = mail.outbox[0]
+        self.assertEqual(message.subject, 'Arkindex project export failed')
+        self.assertListEqual(message.to, [self.user.email])
+        self.assertEqual(message.body, dedent("""
+        Hello Test user,
+
+        An error occurred while exporting the Unit Tests project.
+
+        Error: i ran out of elbow oil
+
+        Please try again or contact your system administrator.
+
+        --
+        Arkindex
+
+        """))
diff --git a/arkindex/templates/export_error.html b/arkindex/templates/export_error.html
new file mode 100644
index 0000000000000000000000000000000000000000..6ac7721b5a54aff5bfb1532d1f8dc1c8fcd529bf
--- /dev/null
+++ b/arkindex/templates/export_error.html
@@ -0,0 +1,12 @@
+{% autoescape off %}
+Hello {{ corpus_export.user.display_name }},
+
+An error occurred while exporting the {{ corpus_export.corpus.name }} project.
+
+Error: {{ error }}
+
+Please try again or contact your system administrator.
+
+--
+Arkindex
+{% endautoescape %}
diff --git a/arkindex/templates/export_success.html b/arkindex/templates/export_success.html
new file mode 100644
index 0000000000000000000000000000000000000000..e6e7f692b325403081e8042ee9556f3a789898cb
--- /dev/null
+++ b/arkindex/templates/export_success.html
@@ -0,0 +1,11 @@
+{% autoescape off %}
+Hello {{ corpus_export.user.display_name }},
+
+Your export for the {{ corpus_export.corpus.name }} project is completed.
+
+You can download it at:
+{{ hostname }}{% url 'api:download-export' pk=corpus_export.id %}
+
+--
+Arkindex
+{% endautoescape %}