From c979429d1d773a4fb54afad6b34f1677b374a785 Mon Sep 17 00:00:00 2001 From: basketmc Date: Thu, 20 Jul 2023 09:21:47 +0200 Subject: [PATCH] =?UTF-8?q?0.17.2:=20-=20betriebsmodus=20"KONNEKTOR"=20->?= =?UTF-8?q?=20=C3=BCber=20den=20konnektor=20verschl=C3=BCsselte=20und=20si?= =?UTF-8?q?gnierte=20mail=20kann=20an=20einen=20normalen=20mailserver=20ge?= =?UTF-8?q?sendet=20werden,=20NUR=20f=C3=BCr=20den=20Test=20angedacht?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../cmdhandler/Pop3GatewayRetrCmdHandler.java | 13 +++- .../cmdhandler/SmtpGatewayRcptCmdHandler.java | 4 +- .../smtp/hook/SmtpGatewayMailHook.java | 14 ++-- .../openkim/log/DefaultLoggerContext.java | 36 +++++++-- .../mail/CheckSendingMailOperation.java | 2 +- .../mail/ComposeEncryptedMailOperation.java | 8 ++ .../pipeline/operation/mail/MailUtils.java | 73 ++++++++++++++++++- .../operation/mail/SendDsnOperation.java | 6 +- .../test/SignEncryptMailTestOperation.java | 8 +- .../OpenKIM_SendMailTest_Formular.html | 4 +- 11 files changed, 145 insertions(+), 25 deletions(-) diff --git a/pom.xml b/pom.xml index c9fd099..b706030 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ net.sberg openkim - 0.17.1 + 0.17.2 openkim Open KIM Client Modul diff --git a/src/main/java/net/sberg/openkim/gateway/pop3/cmdhandler/Pop3GatewayRetrCmdHandler.java b/src/main/java/net/sberg/openkim/gateway/pop3/cmdhandler/Pop3GatewayRetrCmdHandler.java index 6adfce2..fa6d764 100644 --- a/src/main/java/net/sberg/openkim/gateway/pop3/cmdhandler/Pop3GatewayRetrCmdHandler.java +++ b/src/main/java/net/sberg/openkim/gateway/pop3/cmdhandler/Pop3GatewayRetrCmdHandler.java @@ -28,6 +28,7 @@ import net.sberg.openkim.pipeline.operation.mail.CreateDsnOperation; import net.sberg.openkim.pipeline.operation.mail.CreateEmbeddedMessageRfc822Operation; import net.sberg.openkim.pipeline.operation.mail.DecryptVerifyMailOperation; +import net.sberg.openkim.pipeline.operation.mail.MailUtils; import net.sberg.openkim.pipeline.operation.mail.kas.KasIncomingMailOperation; import org.apache.james.protocols.api.Request; import org.apache.james.protocols.api.Response; @@ -110,6 +111,11 @@ private Response doRetr(POP3Session session, Request request) { if (session.getHandlerState() == POP3Session.TRANSACTION) { try { MimeMessage message = (MimeMessage) pop3GatewaySession.getPop3ClientFolder().getMessage(Integer.parseInt(request.getArgument())); + + if (!MailUtils.checkAddressMapping(logger, message, false)) { + throw new IllegalStateException("error on checking of address mapping"); + } + pop3GatewaySession.setGatewayState(EnumPop3GatewayState.PROCESS); byte[] pop3msg = null; @@ -144,7 +150,12 @@ private Response doRetr(POP3Session session, Request request) { message = (MimeMessage) defaultPipelineOperationContext.getEnvironmentValue(KasIncomingMailOperation.NAME, KasIncomingMailOperation.ENV_RESULT_MSG); } - pop3msg = decryptVerify(pop3GatewaySession.getLogger(), pop3GatewaySession.getLogger().getDefaultLoggerContext().getMailServerUsername(), message); + String userMailAddress = pop3GatewaySession.getLogger().getDefaultLoggerContext().getMailServerUsername(); + if (!logger.getDefaultLoggerContext().getKonfiguration().getGatewayTIMode().equals(EnumGatewayTIMode.FULLSTACK) && logger.getDefaultLoggerContext().getSenderAddressMapping().containsKey(userMailAddress)) { + userMailAddress = logger.getDefaultLoggerContext().getSenderAddressMapping().get(userMailAddress); + } + + pop3msg = decryptVerify(pop3GatewaySession.getLogger(), userMailAddress, message); if (!logger.getDefaultLoggerContext().getMailSignVerifyErrorContext().isEmpty()) { CreateDsnOperation createDsnOperation = (CreateDsnOperation) pipelineService.getOperation(CreateDsnOperation.BUILTIN_VENDOR + "." + CreateDsnOperation.NAME); diff --git a/src/main/java/net/sberg/openkim/gateway/smtp/cmdhandler/SmtpGatewayRcptCmdHandler.java b/src/main/java/net/sberg/openkim/gateway/smtp/cmdhandler/SmtpGatewayRcptCmdHandler.java index d587985..153fa2f 100644 --- a/src/main/java/net/sberg/openkim/gateway/smtp/cmdhandler/SmtpGatewayRcptCmdHandler.java +++ b/src/main/java/net/sberg/openkim/gateway/smtp/cmdhandler/SmtpGatewayRcptCmdHandler.java @@ -98,9 +98,9 @@ protected Response doCoreCmd(SMTPSession session, String command, String paramet } else { DefaultLoggerContext loggerContext = ((SmtpGatewaySession) session).getLogger().getDefaultLoggerContext(); - if (!loggerContext.getRecipientAddresses().contains(recipientAddress.asString().toLowerCase())) { + if (!loggerContext.getRecipientAddresses(true).contains(recipientAddress.asString().toLowerCase())) { ((SmtpGatewaySession) session).log("rcpt to: "+recipientAddress.asString().toLowerCase()); - loggerContext.getRecipientAddresses().add(recipientAddress.asString().toLowerCase()); + loggerContext.getRecipientAddresses(true).add(recipientAddress.asString().toLowerCase()); } } } catch (Exception e) { diff --git a/src/main/java/net/sberg/openkim/gateway/smtp/hook/SmtpGatewayMailHook.java b/src/main/java/net/sberg/openkim/gateway/smtp/hook/SmtpGatewayMailHook.java index c2ca251..2622d81 100644 --- a/src/main/java/net/sberg/openkim/gateway/smtp/hook/SmtpGatewayMailHook.java +++ b/src/main/java/net/sberg/openkim/gateway/smtp/hook/SmtpGatewayMailHook.java @@ -31,6 +31,7 @@ import net.sberg.openkim.pipeline.operation.DefaultPipelineOperationContext; import net.sberg.openkim.pipeline.operation.konnektor.vzd.LoadVzdCertsOperation; import net.sberg.openkim.pipeline.operation.mail.CheckSendingMailOperation; +import net.sberg.openkim.pipeline.operation.mail.MailUtils; import net.sberg.openkim.pipeline.operation.mail.SendDsnOperation; import net.sberg.openkim.pipeline.operation.mail.SignEncryptMailOperation; import net.sberg.openkim.pipeline.operation.mail.kas.KasOutgoingMailOperation; @@ -191,6 +192,9 @@ public HookResult onMessage(SMTPSession session, MailEnvelope mailEnvelope) { File tempMailFile = FileUtils.writeToFileDirectory((ByteArrayOutputStream) mailEnvelope.getMessageOutputStream(), "openkim", System.getProperty("java.io.tmpdir")); MimeMessage message = new MimeMessage(Session.getInstance(new Properties()), new FileInputStream(tempMailFile)); + if (!MailUtils.checkAddressMapping(logger, message, true)) { + throw new IllegalStateException("error on checking of address mapping"); + } tempMailFile.delete(); String msgContent = null; @@ -198,23 +202,23 @@ public HookResult onMessage(SMTPSession session, MailEnvelope mailEnvelope) { if (!logger.getDefaultLoggerContext().getKonfiguration().getGatewayTIMode().equals(EnumGatewayTIMode.NO_TI)) { //check sender - List senderAddresses = List.of(logger.getDefaultLoggerContext().getSenderAddress()); + List senderAddresses = List.of(logger.getDefaultLoggerContext().getSenderAddress(false)); if (!checkMailAddresses(smtpGatewaySession, logger.getDefaultLoggerContext().getSenderCerts(), senderAddresses, true, false)) { smtpGatewaySession.getSmtpClient().rset(); smtpGatewaySession.log("mail hook ends - error"); return HookResult.DENY; } - if (logger.getDefaultLoggerContext().getMailaddressCertErrorContext().isError(logger.getDefaultLoggerContext().getSenderAddress())) { + if (logger.getDefaultLoggerContext().getMailaddressCertErrorContext().isError(logger.getDefaultLoggerContext().getSenderAddress(false))) { smtpGatewaySession.getSmtpClient().rset(); return sendDsn(logger, List.of(logger.getDefaultLoggerContext().getMailaddressCertErrorContext()), message, true); } - if (logger.getDefaultLoggerContext().getMailaddressKimVersionErrorContext().isError(logger.getDefaultLoggerContext().getSenderAddress())) { + if (logger.getDefaultLoggerContext().getMailaddressKimVersionErrorContext().isError(logger.getDefaultLoggerContext().getSenderAddress(false))) { smtpGatewaySession.getSmtpClient().rset(); return sendDsn(logger, List.of(logger.getDefaultLoggerContext().getMailaddressKimVersionErrorContext()), message, true); } //check recipients - if (!checkMailAddresses(smtpGatewaySession, logger.getDefaultLoggerContext().getRecipientCerts(), logger.getDefaultLoggerContext().getRecipientAddresses(), false, true)) { + if (!checkMailAddresses(smtpGatewaySession, logger.getDefaultLoggerContext().getRecipientCerts(), logger.getDefaultLoggerContext().getRecipientAddresses(false), false, true)) { smtpGatewaySession.getSmtpClient().rset(); smtpGatewaySession.log("mail hook ends - error"); return HookResult.DENY; @@ -343,7 +347,7 @@ public HookResult onMessage(SMTPSession session, MailEnvelope mailEnvelope) { else { //send rcpt to boolean successfulRcptTo = false; - for (Iterator iterator = logger.getDefaultLoggerContext().getRecipientAddresses().iterator(); iterator.hasNext(); ) { + for (Iterator iterator = logger.getDefaultLoggerContext().getRecipientAddresses(true).iterator(); iterator.hasNext(); ) { String rcptAddress = iterator.next(); int res = ((SmtpGatewaySession) session).getSmtpClient().rcpt("<" + rcptAddress + ">"); if (!SMTPReply.isPositiveCompletion(res)) { diff --git a/src/main/java/net/sberg/openkim/log/DefaultLoggerContext.java b/src/main/java/net/sberg/openkim/log/DefaultLoggerContext.java index 8bd4643..70575ce 100644 --- a/src/main/java/net/sberg/openkim/log/DefaultLoggerContext.java +++ b/src/main/java/net/sberg/openkim/log/DefaultLoggerContext.java @@ -18,11 +18,13 @@ import net.sberg.openkim.common.x509.X509CertificateResult; import net.sberg.openkim.fachdienst.Fachdienst; +import net.sberg.openkim.konfiguration.EnumGatewayTIMode; import net.sberg.openkim.konfiguration.Konfiguration; import net.sberg.openkim.konnektor.Konnektor; import net.sberg.openkim.log.error.*; import java.util.*; +import java.util.stream.Collectors; public class DefaultLoggerContext { @@ -47,10 +49,14 @@ public class DefaultLoggerContext { private String mailServerUsername; private String mailServerPassword; private de.gematik.kim.al.model.AccountLimit accountLimit = new de.gematik.kim.al.model.AccountLimit(); + private String senderAddress; private Map senderCerts = new HashMap<>(); + private Map senderAddressMapping = new HashMap<>(); + private List recipientAddresses = new ArrayList<>(); private Map recipientCerts = new HashMap<>(); + private Map> recipientAddressMapping = new HashMap<>(); private final MailaddressCertErrorContext mailaddressCertErrorContext = new MailaddressCertErrorContext(); private final MailaddressKimVersionErrorContext mailaddressKimVersionErrorContext = new MailaddressKimVersionErrorContext(); @@ -252,15 +258,35 @@ public String getMailServerPassword() { return mailServerPassword; } - public List getRecipientAddresses() { return recipientAddresses; } - + public List getRecipientAddresses(boolean origin) { + if (konfiguration.getGatewayTIMode().equals(EnumGatewayTIMode.FULLSTACK)) { + return recipientAddresses; + } + if (origin) { + return recipientAddresses; + } + if (getRecipientAddressMapping().isEmpty()) { + return recipientAddresses; + } + return getRecipientAddressMapping().values().stream().map(stringStringMap -> stringStringMap.values()).flatMap(Collection::stream).collect(Collectors.toList()); + } public Map getRecipientCerts() { return recipientCerts; } + public Map> getRecipientAddressMapping() { return recipientAddressMapping; } - public String getSenderAddress() { - return senderAddress; + public String getSenderAddress(boolean origin) { + if (konfiguration.getGatewayTIMode().equals(EnumGatewayTIMode.FULLSTACK)) { + return senderAddress; + } + if (origin) { + return senderAddress; + } + if (getSenderAddressMapping().isEmpty()) { + return senderAddress; + } + return getSenderAddressMapping().get(senderAddress); } - public Map getSenderCerts() { return senderCerts; } + public Map getSenderAddressMapping() { return senderAddressMapping; } public de.gematik.kim.al.model.AccountLimit getAccountLimit() { return accountLimit; diff --git a/src/main/java/net/sberg/openkim/pipeline/operation/mail/CheckSendingMailOperation.java b/src/main/java/net/sberg/openkim/pipeline/operation/mail/CheckSendingMailOperation.java index d50bfc1..e0ebe9d 100644 --- a/src/main/java/net/sberg/openkim/pipeline/operation/mail/CheckSendingMailOperation.java +++ b/src/main/java/net/sberg/openkim/pipeline/operation/mail/CheckSendingMailOperation.java @@ -72,7 +72,7 @@ public void execute(DefaultPipelineOperationContext defaultPipelineOperationCont MimeMessage message = (MimeMessage) defaultPipelineOperationContext.getEnvironmentValue(NAME, ENV_MSG); List recipientCerts = new ArrayList<>(logger.getDefaultLoggerContext().getRecipientCerts().values()); - String senderAddress = logger.getDefaultLoggerContext().getSenderAddress(); + String senderAddress = logger.getDefaultLoggerContext().getSenderAddress(false); if (message.getFrom() == null || message.getFrom().length == 0) { logger.logLine("no from header available for senderAddress: " + senderAddress); diff --git a/src/main/java/net/sberg/openkim/pipeline/operation/mail/ComposeEncryptedMailOperation.java b/src/main/java/net/sberg/openkim/pipeline/operation/mail/ComposeEncryptedMailOperation.java index a1da894..4e35ad9 100644 --- a/src/main/java/net/sberg/openkim/pipeline/operation/mail/ComposeEncryptedMailOperation.java +++ b/src/main/java/net/sberg/openkim/pipeline/operation/mail/ComposeEncryptedMailOperation.java @@ -135,6 +135,14 @@ public void execute(DefaultPipelineOperationContext defaultPipelineOperationCont resultMsg.addHeader(MailUtils.X_OPENKIM_TEST_ID, openkimTestId); } + //check on openkim test message -> addressmapping + String addressMapping = (originMimeMessage.getHeader(MailUtils.X_OPENKIM_ADDRESS_MAPPING) != null && originMimeMessage.getHeader(MailUtils.X_OPENKIM_ADDRESS_MAPPING).length > 0) + ? originMimeMessage.getHeader(MailUtils.X_OPENKIM_ADDRESS_MAPPING)[0] + : null; + if (addressMapping != null) { + resultMsg.addHeader(MailUtils.X_OPENKIM_ADDRESS_MAPPING, addressMapping); + } + resultMsg.addHeader(MailUtils.X_KIM_DIENSTKENNUNG, dienstkennung); resultMsg = MailUtils.setRecipients(logger, recipientCerts, originMimeMessage, resultMsg, Message.RecipientType.TO); resultMsg = MailUtils.setRecipients(logger, recipientCerts, originMimeMessage, resultMsg, Message.RecipientType.CC); diff --git a/src/main/java/net/sberg/openkim/pipeline/operation/mail/MailUtils.java b/src/main/java/net/sberg/openkim/pipeline/operation/mail/MailUtils.java index c456791..8161dc9 100644 --- a/src/main/java/net/sberg/openkim/pipeline/operation/mail/MailUtils.java +++ b/src/main/java/net/sberg/openkim/pipeline/operation/mail/MailUtils.java @@ -138,6 +138,77 @@ public static final MimeMessage setRecipients( return resultMessage; } + public static final boolean checkAddressMapping(DefaultLogger logger, MimeMessage msg, boolean sendingMode) throws Exception { + try { + logger.logLine("checkAddressMapping"); + String addressMappingStr = (msg.getHeader(MailUtils.X_OPENKIM_ADDRESS_MAPPING) != null && msg.getHeader(MailUtils.X_OPENKIM_ADDRESS_MAPPING).length > 0) + ? msg.getHeader(MailUtils.X_OPENKIM_ADDRESS_MAPPING)[0] + : null; + if (addressMappingStr == null) { + logger.logLine("checkAddressMapping finished - no mappings available"); + return true; + } + //to|kim-test@sberg.net=uschi@web.de,from|basketmc@gmail.com=uschi@yahoo.de + String[] mappings = addressMappingStr.split(","); + for (int i = 0; i < mappings.length; i++) { + String recOrSender = mappings[i].split("\\|")[0].toLowerCase(); + String mapping = mappings[i].split("\\|")[1]; + String source = mapping.split("=")[0].toLowerCase(); + String target = mapping.split("=")[1].toLowerCase(); + if (!recOrSender.equals(FROM.toLowerCase()) + && + !recOrSender.equals(TO.toLowerCase()) + && + !recOrSender.equals(CC.toLowerCase()) + && + !recOrSender.equals(BCC.toLowerCase()) + ) { + throw new IllegalStateException("falsches Format"); + } + + if (recOrSender.equals(FROM.toLowerCase())) { + logger.getDefaultLoggerContext().getSenderAddressMapping().put(source, target); + } + else { + if (!logger.getDefaultLoggerContext().getRecipientAddressMapping().containsKey(recOrSender)) { + logger.getDefaultLoggerContext().getRecipientAddressMapping().put(recOrSender, new HashMap<>()); + } + logger.getDefaultLoggerContext().getRecipientAddressMapping().get(recOrSender).put(source, target); + } + } + + if (sendingMode) { + String from = msg.getFrom()[0].toString().toLowerCase(); + if (logger.getDefaultLoggerContext().getSenderAddressMapping().containsKey(from)) { + msg.setFrom(logger.getDefaultLoggerContext().getSenderAddressMapping().get(from)); + } + + List types = List.of(Message.RecipientType.TO, Message.RecipientType.CC, Message.RecipientType.BCC); + for (Iterator iterator = types.iterator(); iterator.hasNext(); ) { + Message.RecipientType type = iterator.next(); + Address[] addresses = msg.getRecipients(type); + if (addresses != null && logger.getDefaultLoggerContext().getRecipientAddressMapping().containsKey(type.toString().toLowerCase())) { + msg.removeHeader(type.toString().toLowerCase()); + for (int i = 0; i < addresses.length; i++) { + if (logger.getDefaultLoggerContext().getRecipientAddressMapping().get(type.toString().toLowerCase()).containsKey(addresses[i].toString().toLowerCase())) { + msg.addRecipient(type, new InternetAddress(logger.getDefaultLoggerContext().getRecipientAddressMapping().get(type.toString().toLowerCase()).get(addresses[i].toString().toLowerCase()))); + } else { + msg.addRecipient(type, addresses[i]); + } + } + } + } + } + + return true; + } + catch (Exception e) { + log.error("error on checkAddressMapping", e); + logger.logLine("error on checkAddressMapping"); + throw e; + } + } + public static final boolean checkHeader(DefaultLogger logger, Konnektor konnektor, MimeMessage encryptedMsg, MimeMessage decryptedAndVerifiedMsg, String headerName) throws Exception { try { logger.logLine("check header: " + headerName); @@ -298,7 +369,7 @@ public static final Session createPop3ClientSession( authMethod, host, port, - pop3ClientIdleTimeoutInSeconds * 1000 + pop3ClientIdleTimeoutInSeconds * 1000 ); if (createSSLSocketFactory) { diff --git a/src/main/java/net/sberg/openkim/pipeline/operation/mail/SendDsnOperation.java b/src/main/java/net/sberg/openkim/pipeline/operation/mail/SendDsnOperation.java index a398d36..838efca 100644 --- a/src/main/java/net/sberg/openkim/pipeline/operation/mail/SendDsnOperation.java +++ b/src/main/java/net/sberg/openkim/pipeline/operation/mail/SendDsnOperation.java @@ -177,7 +177,7 @@ else if (errorContext instanceof MailaddressKimVersionErrorContext) { mimeMessage = DsnHelper.createMessage( originMessage, - logger.getDefaultLoggerContext().getSenderAddress(), + logger.getDefaultLoggerContext().getSenderAddress(false), contentBuilder.toString(), "", "", @@ -212,8 +212,8 @@ else if (errorContext instanceof MailaddressKimVersionErrorContext) { logger.logLine("dsn sending - smtp auth: " + res); if (res) { String content = byteArrayOutputStream.toString(); - String[] recs = new String[]{logger.getDefaultLoggerContext().getSenderAddress()}; - res = client.sendSimpleMessage(logger.getDefaultLoggerContext().getSenderAddress(), recs, content); + String[] recs = new String[]{logger.getDefaultLoggerContext().getSenderAddress(false)}; + res = client.sendSimpleMessage(logger.getDefaultLoggerContext().getSenderAddress(false), recs, content); logger.logLine("dsn sending - smtp sent: " + res); } diff --git a/src/main/java/net/sberg/openkim/pipeline/operation/test/SignEncryptMailTestOperation.java b/src/main/java/net/sberg/openkim/pipeline/operation/test/SignEncryptMailTestOperation.java index 0a2329a..e8c3229 100644 --- a/src/main/java/net/sberg/openkim/pipeline/operation/test/SignEncryptMailTestOperation.java +++ b/src/main/java/net/sberg/openkim/pipeline/operation/test/SignEncryptMailTestOperation.java @@ -129,17 +129,17 @@ public void execute(DefaultPipelineOperationContext defaultPipelineOperationCont String to = (String)defaultPipelineOperationContext.getEnvironmentValue(NAME, ENV_TO); if (to != null && !to.isEmpty()) { - logger.getDefaultLoggerContext().getRecipientAddresses().addAll(Arrays.asList(to.split(","))); + logger.getDefaultLoggerContext().getRecipientAddresses(true).addAll(Arrays.asList(to.split(","))); mimeMessage.setRecipients(Message.RecipientType.TO, to); } String cc = (String)defaultPipelineOperationContext.getEnvironmentValue(NAME, ENV_CC); if (cc != null && !cc.isEmpty()) { - logger.getDefaultLoggerContext().getRecipientAddresses().addAll(Arrays.asList(cc.split(","))); + logger.getDefaultLoggerContext().getRecipientAddresses(true).addAll(Arrays.asList(cc.split(","))); mimeMessage.setRecipients(Message.RecipientType.CC, to); } String bcc = (String)defaultPipelineOperationContext.getEnvironmentValue(NAME, ENV_BCC); if (bcc != null && !bcc.isEmpty()) { - logger.getDefaultLoggerContext().getRecipientAddresses().addAll(Arrays.asList(bcc.split(","))); + logger.getDefaultLoggerContext().getRecipientAddresses(true).addAll(Arrays.asList(bcc.split(","))); mimeMessage.setRecipients(Message.RecipientType.BCC, to); } @@ -151,7 +151,7 @@ public void execute(DefaultPipelineOperationContext defaultPipelineOperationCont } //check recipients - if (!checkMailAddresses(logger, logger.getDefaultLoggerContext().getRecipientCerts(), logger.getDefaultLoggerContext().getRecipientAddresses(), false, true)) { + if (!checkMailAddresses(logger, logger.getDefaultLoggerContext().getRecipientCerts(), logger.getDefaultLoggerContext().getRecipientAddresses(true), false, true)) { logger.logLine("load recipient certs ends - error"); throw new IllegalStateException("load recipient certs ends - error"); } diff --git a/src/main/resources/templates/pipelineoperationtest/OpenKIM_SendMailTest_Formular.html b/src/main/resources/templates/pipelineoperationtest/OpenKIM_SendMailTest_Formular.html index 07d7bf4..036d060 100644 --- a/src/main/resources/templates/pipelineoperationtest/OpenKIM_SendMailTest_Formular.html +++ b/src/main/resources/templates/pipelineoperationtest/OpenKIM_SendMailTest_Formular.html @@ -86,8 +86,8 @@ Bitte angeben! -
- +
+