diff --git a/compendium_v2/__init__.py b/compendium_v2/__init__.py
index 9d1b68d063ca54b1cce4e0b32e44e324a2cf2452..187920aca1d14c2aed83879055f3c13458588344 100644
--- a/compendium_v2/__init__.py
+++ b/compendium_v2/__init__.py
@@ -67,6 +67,17 @@ def _create_app_with_db(app_config) -> Flask:
         # for the publishers
         app.config['SQLALCHEMY_BINDS'] = app_config['SQLALCHEMY_BINDS']
 
+    if 'mail' in app_config:
+        mail_config = app_config['mail']
+        app.config['MAIL_ENABLE'] = True
+        app.config['MAIL_SERVER'] = mail_config['MAIL_SERVER']
+        app.config['MAIL_PORT'] = mail_config['MAIL_PORT']
+        app.config['MAIL_SENDER_EMAIL'] = mail_config['MAIL_SENDER_EMAIL']  # email address to send emails from
+        excluded_admins = mail_config.get('MAIL_EXCLUDED_ADMINS', [])
+        app.config['MAIL_EXCLUDED_ADMINS'] = excluded_admins  # list of admin emails not to send emails to
+    else:
+        app.config['MAIL_ENABLE'] = False
+
     db.init_app(app)
     return app
 
diff --git a/compendium_v2/auth/session_management.py b/compendium_v2/auth/session_management.py
index 37be02d952405c8005ddb21cedd9d7f63f8dba4b..4c713edee2e8ad21e6222c7a9226e117b0296519 100644
--- a/compendium_v2/auth/session_management.py
+++ b/compendium_v2/auth/session_management.py
@@ -5,6 +5,7 @@ from datetime import datetime
 from flask_login import LoginManager, current_user  # type: ignore
 from compendium_v2.db import session_scope
 from compendium_v2.db.auth_model import User, ROLES
+from compendium_v2.email import send_mail
 
 
 def admin_required(func):
@@ -45,6 +46,7 @@ def create_user(email: str, fullname: str, oidc_sub: str):
     with session_scope() as session:
         user = User(email=email, fullname=fullname, oidc_sub=oidc_sub)
         session.add(user)
+        send_mail(f'{fullname} has just signed up with the email {email} and provider ID {oidc_sub}')
         return user
 
 
diff --git a/compendium_v2/config.py b/compendium_v2/config.py
index 490f399a55af8bff0a2d0b82e45ef6ae2fbbd6fa..4c67ad9842da0bd6b930f934d52898efb4377cc8 100644
--- a/compendium_v2/config.py
+++ b/compendium_v2/config.py
@@ -17,6 +17,20 @@ CONFIG_SCHEMA = {
             'required': ['client_id', 'client_secret', 'server_metadata_url'],
             'additionalProperties': False
         },
+        'mail': {
+            'type': 'object',
+            'properties': {
+                'MAIL_SERVER': {'type': 'string'},
+                'MAIL_PORT': {'type': 'integer'},
+                'MAIL_SENDER_EMAIL': {'type': 'string', 'format': 'email'},
+                'MAIL_EXCLUDED_ADMINS': {
+                    'type': 'array',
+                    'items': {'type': 'string', 'format': 'email'}
+                }
+            },
+            'required': ['MAIL_SERVER', 'MAIL_PORT', 'MAIL_SENDER_EMAIL'],
+            'additionalProperties': False
+        },
         'SECRET_KEY': {'type': 'string'},
     },
     'required': ['SQLALCHEMY_DATABASE_URI', 'SURVEY_DATABASE_URI', 'SECRET_KEY'],
diff --git a/compendium_v2/email/__init__.py b/compendium_v2/email/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..85008856d3ed82198cc90d888846ec746295bf89
--- /dev/null
+++ b/compendium_v2/email/__init__.py
@@ -0,0 +1,54 @@
+import smtplib
+import threading
+import logging
+from typing import Sequence, Union
+from sqlalchemy import select
+from flask import current_app
+from compendium_v2.db import db
+from compendium_v2.db.auth_model import User, ROLES
+
+logger = logging.getLogger(__name__)
+
+
+def _send_mail(smtp_server, port, sender_email, recipients, message):
+
+    try:
+        with smtplib.SMTP(smtp_server, port) as server:
+            server.sendmail(from_addr=sender_email, to_addrs=recipients, msg=message)
+        logger.debug('Successfully sent email')
+    except Exception:
+        logger.exception('Unable to send email:')
+
+
+def send_mail(
+    contents: str,
+    subject: str = 'New user signed up for Compendium',
+    recipients: Union[str, Sequence[str]] = ''
+):
+    if not current_app.config['MAIL_ENABLE']:
+        logger.warning('No mail configuration, cannot send email.')
+        return
+
+    if not contents or not isinstance(contents, str):
+        raise ValueError('Contents must be a non-empty string.')
+
+    excluded_admins = set(email.lower() for email in current_app.config['MAIL_EXCLUDED_ADMINS'])
+
+    admins = db.session.scalars(select(User).where(User.roles == ROLES.admin)).unique().all()
+
+    admin_emails = [admin.email for admin in admins if admin.email.lower() not in excluded_admins]
+
+    if not recipients:
+        recipients = admin_emails
+
+    subject = subject.replace('\n', ' ')
+    message = f"""Subject: {subject}\n\n{contents}"""
+
+    smtp_server = current_app.config['MAIL_SERVER']
+    port = current_app.config['MAIL_PORT']
+    sender_email = current_app.config['MAIL_SENDER_EMAIL']
+
+    # spin off a thread since this can take some time..
+    logger.debug('Sending email')
+    thread = threading.Thread(target=_send_mail, args=(smtp_server, port, sender_email, recipients, message))
+    thread.start()
diff --git a/config-example.json b/config-example.json
index a04ee059f8b528a5821205dc507765c0e6751aa8..f712e8b4cb8f8c88cbf809350526a41a330afdec 100644
--- a/config-example.json
+++ b/config-example.json
@@ -6,5 +6,13 @@
     "client_secret": "<secret>",
     "server_metadata_url": "https://accounts.google.com/.well-known/openid-configuration"
   },
-  "SECRET_KEY": "changeme"
+  "SECRET_KEY": "changeme",
+  "mail": {
+    "MAIL_SERVER": "mail.geant.net",
+    "MAIL_PORT": 25,
+    "MAIL_SENDER_EMAIL": "compendium@geant.org",
+    "MAIL_EXCLUDED_ADMINS": [
+      "bjarke@nordu.net"
+    ]
+  }
 }
diff --git a/test/conftest.py b/test/conftest.py
index 001aee506856395d69d023cb33d57a2aef8bb204..154265bc3a3fedbd494443132232e80868177957 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -26,7 +26,7 @@ def dummy_config():
 
 
 @pytest.fixture
-def mocked_admin_user(app, mocker):
+def mocked_admin_user(app, test_survey_data, mocker):
     with app.app_context():
         user = User(email='testemail123@email.local', fullname='testfullname', oidc_sub='fakesub', roles=ROLES.admin)
 
@@ -42,7 +42,7 @@ def mocked_admin_user(app, mocker):
 
 
 @pytest.fixture
-def mocked_user(app, mocker):
+def mocked_user(app, test_survey_data, mocker):
     with app.app_context():
         user = User(email='testemail123@email.local', fullname='testfullname', oidc_sub='fakesub')
 
diff --git a/test/test_send_mail.py b/test/test_send_mail.py
new file mode 100644
index 0000000000000000000000000000000000000000..a1725367f4f4230b769f6338760c10c5d48c8d1f
--- /dev/null
+++ b/test/test_send_mail.py
@@ -0,0 +1,16 @@
+from compendium_v2.email import send_mail
+
+
+def test_email(app, mocked_admin_user, mocker):
+
+    def _send_mail(*args, **kwargs):
+        pass
+
+    mocker.patch('compendium_v2.email._send_mail', _send_mail)
+    with app.app_context():
+        app.config['MAIL_ENABLE'] = True
+        app.config['MAIL_SERVER'] = 'localhost'
+        app.config['MAIL_PORT'] = 54655
+        app.config['MAIL_SENDER_EMAIL'] = 'fakesender123@test.local'
+        app.config['MAIL_EXCLUDED_ADMINS'] = []
+        send_mail('testmail321')