diff --git a/CHANGES.rst b/CHANGES.rst
index 04cd3fe4a182568e8e5060a06d3a6e9e3a580fa5..baeccb9c3bd1a277eb09e094047f431b72b42ff0 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -8,12 +8,13 @@
 Changes
 =======
 
-Version 2024.4 (released 2024-11-26, updated 2024-11-27)
+Version 2024.4 (released 2024-11-26, updated 2024-11-29)
 
 - Pin `Flask-Menu`` dependency
 - Add `Invenio-DAMAP` to the dependencies
 - Implement TU Wien user identity generator for connection to DAMAP
 - Cast TISS ID into string for the Invenio-DAMAP integration
+- Send out notification emails when records get published
 
 
 Version 2024.3 (released 2024-10-01, updated 2024-11-13)
diff --git a/invenio_config_tuw/__init__.py b/invenio_config_tuw/__init__.py
index 6fd714337232d6848ebb6eda3a91aee9b0ae930e..65144e5ed31a91c3e78b41fc74fca1b5e4ab9b2c 100644
--- a/invenio_config_tuw/__init__.py
+++ b/invenio_config_tuw/__init__.py
@@ -9,6 +9,6 @@
 
 from .ext import InvenioConfigTUW
 
-__version__ = "2024.4.1"
+__version__ = "2024.4.2"
 
 __all__ = ("__version__", "InvenioConfigTUW")
diff --git a/invenio_config_tuw/services.py b/invenio_config_tuw/services.py
index 4d88d1ef110c0c675d4b98ed375c35c22f2b83ad..fe45ac77253f980832479096c6e15b9bc5f26f1f 100644
--- a/invenio_config_tuw/services.py
+++ b/invenio_config_tuw/services.py
@@ -10,7 +10,11 @@
 """Overrides for core services."""
 
 from invenio_drafts_resources.services.records.components import ServiceComponent
+from invenio_pidstore.models import PIDStatus
 from invenio_rdm_records.services.components import DefaultRecordsComponents
+from invenio_records_resources.services.uow import TaskOp
+
+from .tasks import send_publication_notification_email
 
 
 class ParentAccessSettingsComponent(ServiceComponent):
@@ -24,7 +28,26 @@ class ParentAccessSettingsComponent(ServiceComponent):
         settings.secret_link_expiration = 30
 
 
+class PublicationNotificationComponent(ServiceComponent):
+    """Component for notifying users about the publication of their record."""
+
+    def publish(self, identity, draft=None, record=None, **kwargs):
+        """Register a task to send off the notification email."""
+        # the first time the record gets published, the PID's status
+        # gets set to "R" but that won't have been transferred to the
+        # record's data until the `record.commit()` from the unit of work
+        has_been_published = (
+            draft.pid.status == draft["pid"]["status"] == PIDStatus.REGISTERED
+        )
+
+        if not has_been_published:
+            self.uow.register(
+                TaskOp(send_publication_notification_email, record.pid.pid_value)
+            )
+
+
 TUWRecordsComponents = [
     *DefaultRecordsComponents,
     ParentAccessSettingsComponent,
+    PublicationNotificationComponent,
 ]
diff --git a/invenio_config_tuw/tasks.py b/invenio_config_tuw/tasks.py
index 69e07f3c4b46d528585b4f613f36a7ce498e5f32..92634ce2821e9d6aeb3bcd262257d9348658c869 100644
--- a/invenio_config_tuw/tasks.py
+++ b/invenio_config_tuw/tasks.py
@@ -12,9 +12,12 @@ from typing import List, Optional
 
 import requests
 from celery import shared_task
-from flask import current_app
+from flask import current_app, render_template
 from invenio_access.permissions import system_identity
+from invenio_accounts.proxies import current_datastore
 from invenio_db import db
+from invenio_mail.tasks import send_email
+from invenio_rdm_records.proxies import current_rdm_records_service as records_service
 from invenio_records_resources.services.uow import UnitOfWork
 from invenio_vocabularies.contrib.names.api import Name
 
@@ -134,3 +137,36 @@ def sync_names_from_tiss():
         uow.commit()
 
     return results
+
+
+@shared_task(ignore_result=True)
+def send_publication_notification_email(recid: str, user_id: Optional[str] = None):
+    """Send the record uploader an email about the publication of their record."""
+    record = records_service.read(identity=system_identity, id_=recid)
+    if user_id is not None:
+        user = current_datastore.get_user(user_id)
+    else:
+        owner = record._obj.parent.access.owner
+        if owner is not None and owner.owner_type == "user":
+            user = owner.resolve()
+
+    html_message = render_template(
+        "invenio_theme_tuw/mails/record_published.html",
+        uploader=user,
+        record=record,
+    )
+    message = render_template(
+        "invenio_theme_tuw/mails/record_published.txt",
+        uploader=user,
+        record=record,
+    )
+
+    record_title = record["metadata"]["title"]
+    send_email(
+        {
+            "subject": f'Your record "{record_title}" was published',
+            "html": html_message,
+            "body": message,
+            "recipients": [user.email],
+        }
+    )