diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index a8a64b68984df4e3882dfa82b00d05163cd9ae2e..c3e2e33962f10cf8d4e5d77ea91ab7cf8a2582c2 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -12,7 +12,7 @@ lint:
         - python3 -m pip install .[test]
     script:
         - mypy --install-types --non-interactive
-        - black --check src
+        - black --check -t py310 src
 
 pages:
     image: python
diff --git a/assets/config/inventory.toml b/assets/config/inventory.toml
index a00512da776982e981021e19fd1ea8fcfd5f15ca..3204df39630c0bd0888678a7b6f160945e03ffdc 100644
--- a/assets/config/inventory.toml
+++ b/assets/config/inventory.toml
@@ -17,13 +17,17 @@
 # The the project name that should be used for this freva instance
 # NOTE: this key has to be the first in the file
 project_name = ""
+
 ## Set the path to the SSL certfificate files that is used to make password
 ## queries to the vault server or used as web certfificates.
 [certificates]
+
 ## Path to the public keyfile
 public_keyfile = ""
+
 ## Path to the private keyfile
 privat_keyfile = ""
+
 ## Path to the chain file
 chain_keyfile = ""
 
@@ -63,19 +67,27 @@ hosts = ""
 ##in order to deploy the system correctly
 ##
 [db.config]
+
 ## Config variables for the database service
 port = 3306
 user = ""
 db = ""
+
 ##If you need a different user name you can set it here:
 #ansible_user = "username"
+
 ## You can set the db_host seperately, if none is given (default)
 ## the one from the hostsnames above are taken
-##db_host = ""
+
+db_host = ""
+
 ## Ansible needs a python3 interpreter, which can be set for custom python3 instances
 #ansible_python_interpreter = ""
+
 ##If you need a different user name you can set it here:
+
 #ansible_python_interpreter="/usr/bin/python3"
+
 ##Indicate whether or not to empty any pre-existing folders/docker volumes.
 ##(Useful for a truely fresh start) (default: False)
 wipe = false
@@ -83,12 +95,16 @@ wipe = false
 [solr.config]
 ## Config variables for the solr service
 port = 8983
+
 # Set the memory for the solr server
 mem = "4g"
 ## Ansible needs a python3 interpreter, which can be set for custom python3 instances
+
 #ansible_python_interpreter = ""
+
 ## If you need a different user name you can set it here:
 #ansible_user = "username"
+
 ##Indicate whether or not to empty any pre-existing folders/docker volumes.
 ##(Useful for a truely fresh start) (default: False)
 wipe = false
@@ -98,48 +114,62 @@ wipe = false
 ## List of user(s) that can alter the configuration of the freva cmd line interface
 ## If blank, the user that runs the deployment is chosen
 admins = ""
+
 ## The path where the core should be installed
 install_dir=""
+
 ## Set the path to any existing conda executable on the target machine,
 ## if not existing (default) a tmporary conda distribution will be downloaded
 conda_exec_path=""
+
 ## The directory where the project configuration files will be stored, leave
 ## blank to use the same directory as `install_dir`
 root_dir = ""
+
 ## If you which not to install a core instance but only configure one set the
 ## install variable to false. This can be useful if you have a central instance
 ## of freva deployed and want to setup a project specific configuration that
 ## uses this central instance
 install = true
+
 ## The directory where the user specific output will be stored
 base_dir_location = ""
+
 ## Set the directory holding the user content, like plots, for the web user
 ## interface. Note: after plugin application, display content of the plugin
 ## output will be copied to this directory. The default location of this
 ## directory (if left value left blank) is ${base_dir_location}/share/preview
 preview_path = ""
+
 ## Set the workload manager system, currently available are:
 ## "local", "slurm", "pbs", "lfs", "moab", "oar", "sge"
 scheduler_system = "local"
+
 ## Set the path to the directory that containes the stdout of the plugings,
 ## this directory must be accessible to the web ui. The workload manager
 ## will write the stdout into this directory. Defaults to ${base_dir_location}/share
 scheduler_output_dir = ""
+
 # Set the target architecutre of the system where the backend will be installed
 # to. You can choose from the following options:
 # Linux-x86_64 (default), Linux-aarch64, Linux-ppc64le, Linux-s390x, MacOSX-x86_64
 arch = "Linux-x86_64"
+
 ## If you need to install the core or its configuration as a different user you can
 ## set the ansible_become_user variable, this will install the the core as a
 ## different user
 #ansible_become_user = "username"
+
 ##If you need a different user name you can set it here:
 #ansible_user = "username"
+
 ## Ansible needs a python3 interpreter, which can be set for custom python3 instances
 #ansible_python_interpreter = ""
+
 ## The core deployment needs git, if git is not in the default PATH vraiable
 ## you can set the path to the git executable
 #git_path = ""
+
 ##Indicate whether or not to empty any pre-existing folders/docker volumes.
 ##(Useful for a truely fresh start) (default: False)
 wipe = false
@@ -148,69 +178,99 @@ wipe = false
 [web.config]
 ## List of user that can alter the configuration of freva web
 project_website = "www.freva.dkrz.de"
+
 ## Ansible needs a python3 interpreter, which can be set for custom python3 instances
 #ansible_python_interpreter = ""
+
 ##If you need a different user name you can set it here:
 #ansible_user = "username"
+
 ##Set html colors
 main_color = "Tomato"
 border_color = "#6c2e1f"
 hover_color = "#d0513a"
+
 ## The about us text is a small blurb about freva within the project
 about_us_text = ""
+
 ## Set the path to the institution logo, this should be the path to the logo
 ## as seen by the target system
 institution_logo = "/path/to/logo/on/target/machine"
-## Set a list of email addresses for contacts
-contacts = [""]
+
+## Set a an email addresses acting a a contact point for users
+contacts = ""
+
+## Set the smpt email server that will be used to send emails to contacts via the web ui
+email_host = ""
+
 ## Now set postal address
 imprint = "Project name, German Climate Computing Centre (DKRZ), Bundesstr. 45a, 20146 Hamburg, Germany."
+
 ## Here you can set a lengthy project description.
 ## You can also set a path to a filename that contains the information.
 ## Instead of text you can set a path to a file containing the text, like a html file.
 homepage_text = "Bal bla bla."
+
 ## Set a one line blurb of the project
 homepage_heading = "Short description of the project."
+
 ## Set the name of the project/institution
 institution_name = "Freva"
+
 ## Set the slurm scheduler host
 scheduler_host = ["levante.dkrz.de"]
+
 ## Settings for ldap
+
 ## Ldap server name(s)
 auth_ldap_server_uri = "ldap://idm-dmz.dkrz.de"
+
 ## Set the group that will be allowed to log on
 allowed_group = "test_group"
+
 ## Set the ldap search user base
 ldap_user_base = "cn=users,cn=accounts,dc=dkrz,dc=de"
+
 ## Set the ldap search group base, note: do not add the allowed_group as it will be auto added
 ldap_group_base = "cn=groups,cn=accounts,dc=dkrz,dc=de"
+
 ## distinguished name (dn) for the ldap user
 ldap_user_dn = "uid=dkrzagent,cn=sysaccounts,cn=etc,dc=dkrz,dc=de"
+
 ## use encrypted ldap connection (needs to be configured)
 auth_ldap_start_tls = false
+
 ## Set ldap last name search key
 ldap_last_name_field = "givenname"
+
 ## Set ldap first name search key
 ldap_first_name_field = "sn"
+
 ## Set ldap email earch key
 ldap_email_name_field = "mail"
-# Set the ldap group class name
+
+## Set the ldap group class name
 ldap_group_class = "groupOfNames"
-# Set the ldap group type, available values are are [posix, nested]
+
+## Set the ldap group type, available values are are [posix, nested]
 ldap_group_type = "nested"
-# Set the ldap tools class for users
-ldap_model = "MiklipUserInformation"
 
+## Set the ldap tools class for users
+ldap_model = "MiklipUserInformation"
 
 ## set the passwd for the ldap user
 ldap_user_pw = "dkrzprox"
+
 #######
 ## Set the hosts that are allowed to execute wsgi code
 allowed_hosts = ["www.freva.dkrz.de", "localhost"]
+
 ## Turn on/off debug mode on the website
 debug=false
+
 ## Which plugin id should be used for the web tour
 guest_tour_result = 105
+
 ## Set the menu entries
 # Menu entries consist of three entries these are:
 # [Label, url, html_id] -> e.g Plugins, plugins:home, plugin_menu
diff --git a/assets/playbooks/web-server-playbook.yml b/assets/playbooks/web-server-playbook.yml
index 915832ac6a004ec575f2626d9fa08902d83ed3aa..bb68f053435f8284f228da18a5492c3131739799 100644
--- a/assets/playbooks/web-server-playbook.yml
+++ b/assets/playbooks/web-server-playbook.yml
@@ -1,6 +1,15 @@
 ---
+- hosts: vault
+  vars:
+    - ansible_python_interpreter: "{{ vault_ansible_python_interpreter }}"
+  tasks:
+    - name: Inserting email secrets
+      become: true
+      shell: >
+        /usr/local/bin/docker-or-podman exec -it {{ vault_name }}
+        vault kv put kv/email username={{vault_email_user}}
+        password='{{vault_email_password}}'
 - hosts: core
-
   vars:
     - ansible_python_interpreter: "{{ core_ansible_python_interpreter }}"
     - ansible_become_user: "{{ core_ansible_become_user if core_ansible_become_user is defined else 'root' }}"
diff --git a/assets/vault/runserver.py b/assets/vault/runserver.py
index fd16e744aaf93eeeda11005de6993ca634a2eeb9..3dd027bb7a100d078cc11614bc44a8fb59c58927 100644
--- a/assets/vault/runserver.py
+++ b/assets/vault/runserver.py
@@ -85,8 +85,9 @@ class Vault(Resource):
         --------
             dict: status information
         """
+        out, status = {}, 401
         if public_key != os.environ["ROOT_PW"]:
-            return jsonify({"status": "fail"})
+            return out, status
         _, token = read_key()
         # Get the information from the vault
         url = f"http://127.0.0.1:8200/v1/kv/data/read-eval"
@@ -94,7 +95,7 @@ class Vault(Resource):
         out = requests.get(url, headers=headers).json()["data"]
         out["data"]["db.passwd"] = entry
         r = requests.post(url, json=out, headers=headers)
-        return jsonify({"status": "success"})
+        return {}, 201
 
     def get(self, entry, public_key):
         """Get method, for getting vault information.
@@ -114,15 +115,32 @@ class Vault(Resource):
         --------
             dict: Vault information
         """
-        out = ""
+        out = {}
+        status = 401
+        _, token = read_key()
+        if public_key != self.public_key:
+            return out, 401
+        if entry == "token":
+            return {"X-Vault-Token": token}, 200
         if entry == "data":
-            _, token = read_key()
             # Get the information from the vault
-            out = requests.get(
-                f"http://127.0.0.1:8200/v1/kv/data/read-eval",
+            req = requests.get(
+                "http://127.0.0.1:8200/v1/kv/data/read-eval",
+                headers={"X-Vault-Token": token},
+            )
+        else:
+            req = requests.get(
+                f"http://127.0.0.1:8200/v1/kv/data/{entry}",
                 headers={"X-Vault-Token": token},
-            ).json()["data"]["data"]
-        return jsonify(out)
+            )
+            out = req.json()["data"]["data"]
+            status = req.status_code
+        try:
+            out = req.json()["data"]["data"]
+            status = req.status_code
+        except KeyError:
+            out = req.json()
+        return out, status
 
 
 api.add_resource(Vault, "/vault/<entry>/<public_key>")  # Route_3
diff --git a/src/freva_deployment/deploy.py b/src/freva_deployment/deploy.py
index 571e422b5469eb7e47ae4cfca7929780da923347..1f1b1e91699643c00bd53e06c788906b3fb1cf5b 100644
--- a/src/freva_deployment/deploy.py
+++ b/src/freva_deployment/deploy.py
@@ -20,6 +20,7 @@ from .utils import (
     asset_dir,
     config_dir,
     get_passwd,
+    get_email_credentials,
     logger,
     upload_server_map,
     RichConsole,
@@ -57,6 +58,7 @@ class DeployFactory:
 
         self._config_keys: list[str] = []
         self.master_pass: str = ""
+        self.email_password: str = ""
         self._td: TemporaryDirectory = TemporaryDirectory(prefix="inventory")
         self.inventory_file: Path = Path(self._td.name) / "inventory.yaml"
         self.eval_conf_file: Path = Path(self._td.name) / "evaluation_system.conf"
@@ -107,8 +109,8 @@ class DeployFactory:
         self.cfg["vault"]["config"]["root_passwd"] = self.master_pass
         self.cfg["vault"]["config"]["passwd"] = self.db_pass
         self.cfg["vault"]["config"]["keyfile"] = self.public_key_file
-        self.cfg["vault"]["config"]["email"] = ",".join(
-            self.cfg["web"]["config"].get("contacts", [])
+        self.cfg["vault"]["config"]["email"] = self.cfg["web"]["config"].get(
+            "contacts", ""
         )
 
     def _prep_db(self) -> None:
@@ -126,8 +128,8 @@ class DeployFactory:
         if not db_host:
             self.cfg["db"]["config"]["host"] = host
         self.cfg["db"]["config"].setdefault("port", "3306")
-        self.cfg["db"]["config"]["email"] = ",".join(
-            self.cfg["web"]["config"].get("contacts", [])
+        self.cfg["db"]["config"]["email"] = self.cfg["web"]["config"].get(
+            "contacts", ""
         )
         self._prep_vault()
 
@@ -139,8 +141,8 @@ class DeployFactory:
             self.cfg["solr"]["config"][key] = (
                 self.cfg["solr"]["config"].get(key) or default
             )
-        self.cfg["solr"]["config"]["email"] = ",".join(
-            self.cfg["web"]["config"].get("contacts", [])
+        self.cfg["solr"]["config"]["email"] = self.cfg["web"]["config"].get(
+            "contacts", ""
         )
 
     def _prep_core(self) -> None:
@@ -246,6 +248,13 @@ class DeployFactory:
             self.cfg[key]["config"]["config_toml_file"] = str(self.web_conf_file)
         if not self.master_pass:
             self.master_pass = get_passwd()
+        email_user, self.email_password = get_email_credentials()
+        self._prep_vault()
+        self.cfg["vault"]["config"]["ansible_python_interpreter"] = self.cfg["db"][
+            "config"
+        ].get("ansible_python_interpreter", "/usr/bin/python3")
+        self.cfg["vault"]["config"]["email_user"] = email_user
+        self.cfg["vault"]["config"]["email_password"] = self.email_password
         self.cfg["web"]["config"]["root_passwd"] = self.master_pass
         self.cfg["web"]["config"]["private_keyfile"] = self.private_key_file
         self.cfg["web"]["config"]["public_keyfile"] = self.public_key_file
@@ -474,13 +483,10 @@ class DeployFactory:
         self.create_eval_config()
         with self.inventory_file.open("w") as f_obj:
             f_obj.write(inventory)
-        if self.master_pass:
-            inventory_str = inventory.replace(
-                self.master_pass, "*" * len(self.master_pass)
-            )
-        else:
-            inventory_str = inventory
-        RichConsole.print(inventory_str, style="bold", markup=True)
+        for passwd in (self.email_password, self.master_pass):
+            if passwd:
+                inventory = inventory.replace(passwd, "*" * len(passwd))
+        RichConsole.print(inventory, style="bold", markup=True)
         logger.info("Playing the playbooks with ansible")
         RichConsole.print(
             "[b]Note:[/] The [blue]BECOME[/] password refers to the "
diff --git a/src/freva_deployment/ui/deployment_tui/deploy_forms.py b/src/freva_deployment/ui/deployment_tui/deploy_forms.py
index 076fa0e122160ddc3cc21ac8457f032ce37bf192..7fa14df2397369e6cd3c22c7d10c41ba12a7b5a3 100644
--- a/src/freva_deployment/ui/deployment_tui/deploy_forms.py
+++ b/src/freva_deployment/ui/deployment_tui/deploy_forms.py
@@ -228,7 +228,7 @@ class WebScreen(BaseForm):
 
     def _add_widgets(self) -> None:
         """Add widgets to the screen."""
-        self.list_keys = "contacts", "imprint", "scheduler_host"
+        self.list_keys = "imprint", "scheduler_host"
         cfg = self.get_config(self.step)
         for key in self.list_keys:
             if key in cfg and isinstance(cfg[key], str):
@@ -298,9 +298,18 @@ class WebScreen(BaseForm):
                 self.add_widget_intelligent(
                     npyscreen.TitleText,
                     name=f"{self.num}Contact email address:",
-                    value=",".join(
-                        cast(List[str], cfg.get("contacts", "admin@freva.dkrz.de"))
+                    value=str(cfg.get("contacts", "data@dkrz.de")),
+                ),
+                True,
+            ),
+            email_host=(
+                self.add_widget_intelligent(
+                    npyscreen.TitleText,
+                    name=(
+                        f"{self.num}Smtp email that will be used to send "
+                        "emails to the contacts via the web ui"
                     ),
+                    value=cfg.get("email_host", "mailhost.dkrz.de"),
                 ),
                 True,
             ),
diff --git a/src/freva_deployment/utils.py b/src/freva_deployment/utils.py
index 77f10eb42e939f2a9879ea29037b5798fe22506f..c90fa91d44b9e794db72521dabdf299d729c270d 100644
--- a/src/freva_deployment/utils.py
+++ b/src/freva_deployment/utils.py
@@ -161,6 +161,25 @@ def upload_server_map(
         logger.error("Could not update server information %s", req.json())
 
 
+def get_email_credentials() -> tuple[str, str]:
+    """Read login credentials for email server.
+
+    Returns
+    =======
+    tuple: username and password
+    """
+
+    msg = (
+        "\nThe web will need login credentials to connect to the [b green]mail server [/]"
+        "that has been set up.\nYou should now enter your [it]login credentials[/].\n"
+        "[b]Note:[/]These credentials will be securely stored in an encrypted vault\n"
+    )
+    RichConsole.print(msg)
+    username = Prompt.ask("[green b]Username[/] for mail server")
+    password = Prompt.ask("[green b]Password[/] for mail server", password=True)
+    return username, password
+
+
 def get_passwd(min_characters: int = 8) -> str:
     """Create a secure pasword.