diff --git a/digiwf-coverage/pom.xml b/digiwf-coverage/pom.xml
index a4bf9b5109..48434769cd 100644
--- a/digiwf-coverage/pom.xml
+++ b/digiwf-coverage/pom.xml
@@ -159,6 +159,11 @@
digiwf-dms-integration-service
${project.version}
+
+ de.muenchen.oss.digiwf
+ digiwf-email-api
+ ${project.version}
+
diff --git a/digiwf-libs/digiwf-email/digiwf-email-api/pom.xml b/digiwf-libs/digiwf-email/digiwf-email-api/pom.xml
new file mode 100644
index 0000000000..4abdbba3d0
--- /dev/null
+++ b/digiwf-libs/digiwf-email/digiwf-email-api/pom.xml
@@ -0,0 +1,42 @@
+
+
+ 4.0.0
+
+ de.muenchen.oss.digiwf
+ digiwf-email
+ 1.3.0-SNAPSHOT
+
+
+ digiwf-email-api
+
+
+
+ org.springframework.boot
+ spring-boot-starter-mail
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+ org.mockito
+ mockito-junit-jupiter
+ test
+
+
+
+
diff --git a/digiwf-libs/digiwf-email/digiwf-email-api/src/main/java/de/muenchen/oss/digiwf/email/api/DigiwfEmailApi.java b/digiwf-libs/digiwf-email/digiwf-email-api/src/main/java/de/muenchen/oss/digiwf/email/api/DigiwfEmailApi.java
new file mode 100644
index 0000000000..2be10864cf
--- /dev/null
+++ b/digiwf-libs/digiwf-email/digiwf-email-api/src/main/java/de/muenchen/oss/digiwf/email/api/DigiwfEmailApi.java
@@ -0,0 +1,19 @@
+package de.muenchen.oss.digiwf.email.api;
+
+import de.muenchen.oss.digiwf.email.model.FileAttachment;
+import jakarta.mail.MessagingException;
+
+import java.util.List;
+
+public interface DigiwfEmailApi {
+
+
+ void sendMail(String receivers, String subject, String body, String replyTo) throws MessagingException;
+
+ void sendMail(String receivers, String subject, String body, String replyTo, String receiversCc, String receiversBcc) throws MessagingException;
+
+ void sendMailWithAttachments(String receivers, String subject, String body, String replyTo, List attachments) throws MessagingException;
+
+ void sendMailWithAttachments(String receivers, String subject, String body, String replyTo, String receiversCc, String receiversBcc, List attachments) throws MessagingException;
+
+}
diff --git a/digiwf-libs/digiwf-email/digiwf-email-api/src/main/java/de/muenchen/oss/digiwf/email/impl/DigiwfEmailApiImpl.java b/digiwf-libs/digiwf-email/digiwf-email-api/src/main/java/de/muenchen/oss/digiwf/email/impl/DigiwfEmailApiImpl.java
new file mode 100644
index 0000000000..fe62069607
--- /dev/null
+++ b/digiwf-libs/digiwf-email/digiwf-email-api/src/main/java/de/muenchen/oss/digiwf/email/impl/DigiwfEmailApiImpl.java
@@ -0,0 +1,74 @@
+package de.muenchen.oss.digiwf.email.impl;
+
+import de.muenchen.oss.digiwf.email.api.DigiwfEmailApi;
+import de.muenchen.oss.digiwf.email.model.FileAttachment;
+import jakarta.mail.Message;
+import jakarta.mail.MessagingException;
+import jakarta.mail.internet.InternetAddress;
+import jakarta.mail.internet.MimeMessage;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import lombok.val;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.MimeMessageHelper;
+
+import java.util.List;
+
+@Slf4j
+@RequiredArgsConstructor
+public class DigiwfEmailApiImpl implements DigiwfEmailApi {
+
+ private final JavaMailSender mailSender;
+ private final String fromAddress;
+
+ @Override
+ public void sendMail(String receivers, String subject, String body, String replyTo) throws MessagingException {
+ this.sendMailWithAttachments(receivers, subject, body, replyTo, null, null, List.of());
+ }
+
+ @Override
+ public void sendMail(String receivers, String subject, String body, String replyTo, String receiversCc, String receiversBcc) throws MessagingException {
+ this.sendMailWithAttachments(receivers, subject, body, replyTo, receiversCc, receiversBcc, List.of());
+ }
+
+ @Override
+ public void sendMailWithAttachments(String receivers, String subject, String body, String replyTo, List attachments) throws MessagingException {
+ this.sendMailWithAttachments(receivers, subject, body, replyTo, null, null, attachments);
+ }
+
+ @Override
+ public void sendMailWithAttachments(String receivers, String subject, String body, String replyTo, String receiversCc, String receiversBcc, List attachments) throws MessagingException {
+ final MimeMessage mimeMessage = this.mailSender.createMimeMessage();
+
+ mimeMessage.setRecipients(Message.RecipientType.TO, InternetAddress.parse(receivers));
+
+ if (StringUtils.isNotEmpty(receiversCc)) {
+ mimeMessage.setRecipients(Message.RecipientType.CC, InternetAddress.parse(receiversCc));
+ }
+ if (StringUtils.isNotEmpty(receiversCc)) {
+ mimeMessage.setRecipients(Message.RecipientType.BCC, InternetAddress.parse(receiversBcc));
+ }
+
+ final var helper = new MimeMessageHelper(mimeMessage, true);
+
+ helper.setSubject(subject);
+ helper.setText(subject);
+ helper.setFrom(this.fromAddress);
+
+ if (StringUtils.isNotBlank(replyTo)) {
+ helper.setReplyTo(replyTo);
+ }
+
+ // mail attachments
+ if (attachments != null) {
+ for (val attachment : attachments) {
+ helper.addAttachment(attachment.getFileName(), attachment.getFile());
+ }
+ }
+
+ this.mailSender.send(mimeMessage);
+ log.info("Mail {} sent to {}.", subject, receivers);
+ }
+
+}
diff --git a/digiwf-libs/digiwf-email/digiwf-email-api/src/main/java/de/muenchen/oss/digiwf/email/model/FileAttachment.java b/digiwf-libs/digiwf-email/digiwf-email-api/src/main/java/de/muenchen/oss/digiwf/email/model/FileAttachment.java
new file mode 100644
index 0000000000..f5a319002e
--- /dev/null
+++ b/digiwf-libs/digiwf-email/digiwf-email-api/src/main/java/de/muenchen/oss/digiwf/email/model/FileAttachment.java
@@ -0,0 +1,17 @@
+package de.muenchen.oss.digiwf.email.model;
+
+import jakarta.mail.util.ByteArrayDataSource;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+
+@Data
+@RequiredArgsConstructor
+@AllArgsConstructor
+public class FileAttachment {
+
+ private String fileName;
+
+ private ByteArrayDataSource file;
+
+}
diff --git a/digiwf-libs/digiwf-email/digiwf-email-api/src/test/java/de/muenchen/oss/digiwf/email/DigiwfEmailApiImplTest.java b/digiwf-libs/digiwf-email/digiwf-email-api/src/test/java/de/muenchen/oss/digiwf/email/DigiwfEmailApiImplTest.java
new file mode 100644
index 0000000000..b7373669d7
--- /dev/null
+++ b/digiwf-libs/digiwf-email/digiwf-email-api/src/test/java/de/muenchen/oss/digiwf/email/DigiwfEmailApiImplTest.java
@@ -0,0 +1,95 @@
+package de.muenchen.oss.digiwf.email;
+
+import de.muenchen.oss.digiwf.email.api.DigiwfEmailApi;
+import de.muenchen.oss.digiwf.email.impl.DigiwfEmailApiImpl;
+import de.muenchen.oss.digiwf.email.model.FileAttachment;
+import jakarta.mail.MessagingException;
+import jakarta.mail.Session;
+import jakarta.mail.internet.MimeMessage;
+import jakarta.mail.util.ByteArrayDataSource;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.springframework.mail.javamail.JavaMailSender;
+
+import java.util.List;
+
+import static org.mockito.Mockito.*;
+
+class DigiwfEmailApiImplTest {
+
+
+ private final JavaMailSender javaMailSender = mock(JavaMailSender.class);
+ private DigiwfEmailApi digiwfEmailApi;
+
+ // test data
+ private final String receiver = "mailReceiver1@muenchen.de,mailReceiver2@muenchen.de";
+ private final String receiverCC = "receiverCC@muenchen.de";
+ private final String receiverBCC = "receiverBCC@muenchen.de";
+ private final String subject = "Test Mail";
+ private final String body = "This is a test mail";
+ private final String replyTo = "digiwf@muenchen.de";
+
+
+ @BeforeEach
+ void setUp() {
+ when(this.javaMailSender.createMimeMessage()).thenReturn(new MimeMessage((Session) null));
+ this.digiwfEmailApi = new DigiwfEmailApiImpl(this.javaMailSender, "digiwf@muenchen.de");
+ }
+
+ @Test
+ void sendSimpleMail() throws MessagingException {
+ this.digiwfEmailApi.sendMail(this.receiver, this.subject, this.body, this.replyTo);
+
+ final ArgumentCaptor messageArgumentCaptor = ArgumentCaptor.forClass(MimeMessage.class);
+ verify(this.javaMailSender).send(messageArgumentCaptor.capture());
+
+ Assertions.assertEquals(2, messageArgumentCaptor.getValue().getAllRecipients().length);
+ Assertions.assertEquals(1, messageArgumentCaptor.getValue().getReplyTo().length);
+ Assertions.assertEquals(this.subject, messageArgumentCaptor.getValue().getSubject());
+ }
+
+ @Test
+ void sendMailWithCCAndBCC() throws MessagingException {
+ this.digiwfEmailApi.sendMail(this.receiver, this.subject, this.body, this.replyTo, this.receiverCC, this.receiverBCC);
+
+ final ArgumentCaptor messageArgumentCaptor = ArgumentCaptor.forClass(MimeMessage.class);
+ verify(this.javaMailSender).send(messageArgumentCaptor.capture());
+
+ Assertions.assertEquals(4, messageArgumentCaptor.getValue().getAllRecipients().length);
+ Assertions.assertEquals(1, messageArgumentCaptor.getValue().getReplyTo().length);
+ Assertions.assertEquals(this.subject, messageArgumentCaptor.getValue().getSubject());
+ }
+
+ @Test
+ void sendMailWithAttachments() throws MessagingException {
+ final List fileAttachments = List.of(
+ new FileAttachment("Testanhang", new ByteArrayDataSource("FooBar".getBytes(), "text/plain"))
+ );
+ this.digiwfEmailApi.sendMailWithAttachments(this.receiver, this.subject, this.body, this.replyTo, fileAttachments);
+
+ final ArgumentCaptor messageArgumentCaptor = ArgumentCaptor.forClass(MimeMessage.class);
+ verify(this.javaMailSender).send(messageArgumentCaptor.capture());
+
+ Assertions.assertEquals(2, messageArgumentCaptor.getValue().getAllRecipients().length);
+ Assertions.assertEquals(1, messageArgumentCaptor.getValue().getReplyTo().length);
+ Assertions.assertEquals(this.subject, messageArgumentCaptor.getValue().getSubject());
+ }
+
+ @Test
+ void sendMailWithReceiversCCAndBCCAndAttachments() throws MessagingException {
+ final List fileAttachments = List.of(
+ new FileAttachment("Testanhang", new ByteArrayDataSource("FooBar".getBytes(), "text/plain"))
+ );
+ this.digiwfEmailApi.sendMailWithAttachments(this.receiver, this.subject, this.body, this.replyTo, this.receiverCC, this.receiverBCC, fileAttachments);
+
+ final ArgumentCaptor messageArgumentCaptor = ArgumentCaptor.forClass(MimeMessage.class);
+ verify(this.javaMailSender).send(messageArgumentCaptor.capture());
+
+ Assertions.assertEquals(4, messageArgumentCaptor.getValue().getAllRecipients().length);
+ Assertions.assertEquals(1, messageArgumentCaptor.getValue().getReplyTo().length);
+ Assertions.assertEquals(this.subject, messageArgumentCaptor.getValue().getSubject());
+ }
+
+}
diff --git a/digiwf-libs/digiwf-email/digiwf-email-starter/pom.xml b/digiwf-libs/digiwf-email/digiwf-email-starter/pom.xml
new file mode 100644
index 0000000000..94eae7e419
--- /dev/null
+++ b/digiwf-libs/digiwf-email/digiwf-email-starter/pom.xml
@@ -0,0 +1,31 @@
+
+
+ 4.0.0
+
+ de.muenchen.oss.digiwf
+ digiwf-email
+ 1.3.0-SNAPSHOT
+
+
+ digiwf-email-starter
+
+
+
+ de.muenchen.oss.digiwf
+ digiwf-email-api
+ ${project.version}
+
+
+ org.springframework.boot
+ spring-boot
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+
+
diff --git a/digiwf-libs/digiwf-email/digiwf-email-starter/src/main/java/de/muenchen/oss/digiwf/email/configuration/DigiwfEmailAutoConfiguration.java b/digiwf-libs/digiwf-email/digiwf-email-starter/src/main/java/de/muenchen/oss/digiwf/email/configuration/DigiwfEmailAutoConfiguration.java
new file mode 100644
index 0000000000..9e5e443ec0
--- /dev/null
+++ b/digiwf-libs/digiwf-email/digiwf-email-starter/src/main/java/de/muenchen/oss/digiwf/email/configuration/DigiwfEmailAutoConfiguration.java
@@ -0,0 +1,24 @@
+package de.muenchen.oss.digiwf.email.configuration;
+
+import de.muenchen.oss.digiwf.email.api.DigiwfEmailApi;
+import de.muenchen.oss.digiwf.email.impl.DigiwfEmailApiImpl;
+import de.muenchen.oss.digiwf.email.properties.CustomMailProperties;
+import lombok.RequiredArgsConstructor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.mail.javamail.JavaMailSender;
+
+@RequiredArgsConstructor
+@EnableConfigurationProperties(value = CustomMailProperties.class)
+public class DigiwfEmailAutoConfiguration {
+
+ private final CustomMailProperties customMailProperties;
+
+ @ConditionalOnMissingBean
+ @Bean
+ public DigiwfEmailApi digiwfEmailApi(final JavaMailSender javaMailSender) {
+ return new DigiwfEmailApiImpl(javaMailSender, this.customMailProperties.getFromAddress());
+ }
+
+}
diff --git a/digiwf-libs/digiwf-email/digiwf-email-starter/src/main/java/de/muenchen/oss/digiwf/email/properties/CustomMailProperties.java b/digiwf-libs/digiwf-email/digiwf-email-starter/src/main/java/de/muenchen/oss/digiwf/email/properties/CustomMailProperties.java
new file mode 100644
index 0000000000..050d401ee5
--- /dev/null
+++ b/digiwf-libs/digiwf-email/digiwf-email-starter/src/main/java/de/muenchen/oss/digiwf/email/properties/CustomMailProperties.java
@@ -0,0 +1,15 @@
+package de.muenchen.oss.digiwf.email.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@Data
+@ConfigurationProperties(prefix = "io.muenchendigital.digiwf.mail")
+public class CustomMailProperties {
+
+ /**
+ * Sender mail address.
+ */
+ private String fromAddress;
+
+}
diff --git a/digiwf-libs/digiwf-email/digiwf-email-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/digiwf-libs/digiwf-email/digiwf-email-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000000..4be2bbc01a
--- /dev/null
+++ b/digiwf-libs/digiwf-email/digiwf-email-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+de.muenchen.oss.digiwf.email.configuration.DigiwfEmailAutoConfiguration
diff --git a/digiwf-libs/digiwf-email/pom.xml b/digiwf-libs/digiwf-email/pom.xml
new file mode 100644
index 0000000000..923f8d31c2
--- /dev/null
+++ b/digiwf-libs/digiwf-email/pom.xml
@@ -0,0 +1,20 @@
+
+
+ 4.0.0
+
+ de.muenchen.oss.digiwf
+ digiwf-libs
+ 1.3.0-SNAPSHOT
+
+
+ digiwf-email
+ pom
+
+
+ digiwf-email-api
+ digiwf-email-starter
+
+
+
diff --git a/digiwf-libs/pom.xml b/digiwf-libs/pom.xml
index e00468c78d..abd1c0beb4 100644
--- a/digiwf-libs/pom.xml
+++ b/digiwf-libs/pom.xml
@@ -24,6 +24,7 @@
digiwf-message
digiwf-spring-security
digiwf-spring-logging-and-tracing
+ digiwf-email