001/*- 002 * #%L 003 * HAPI FHIR - Server Framework 004 * %% 005 * Copyright (C) 2014 - 2024 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.rest.server.mail; 021 022import jakarta.annotation.Nonnull; 023import org.simplejavamail.MailException; 024import org.simplejavamail.api.email.Email; 025import org.simplejavamail.api.email.Recipient; 026import org.simplejavamail.api.mailer.Mailer; 027import org.simplejavamail.api.mailer.config.TransportStrategy; 028import org.simplejavamail.mailer.MailerBuilder; 029import org.slf4j.Logger; 030import org.slf4j.LoggerFactory; 031 032import java.util.List; 033import java.util.Objects; 034import java.util.function.Consumer; 035import java.util.stream.Collectors; 036 037public class MailSvc implements IMailSvc { 038 private static final Logger ourLog = LoggerFactory.getLogger(MailSvc.class); 039 040 private final MailConfig myMailConfig; 041 private final Mailer myMailer; 042 043 public MailSvc(@Nonnull MailConfig theMailConfig) { 044 Objects.requireNonNull(theMailConfig); 045 myMailConfig = theMailConfig; 046 myMailer = makeMailer(myMailConfig); 047 } 048 049 @Override 050 public void sendMail(@Nonnull List<Email> theEmails) { 051 Objects.requireNonNull(theEmails); 052 theEmails.forEach(theEmail -> send(theEmail, new OnSuccess(theEmail), new ErrorHandler(theEmail))); 053 } 054 055 @Override 056 public void sendMail(@Nonnull Email theEmail) { 057 send(theEmail, new OnSuccess(theEmail), new ErrorHandler(theEmail)); 058 } 059 060 @Override 061 public void sendMail( 062 @Nonnull Email theEmail, @Nonnull Runnable theOnSuccess, @Nonnull Consumer<Throwable> theErrorHandler) { 063 send(theEmail, theOnSuccess, theErrorHandler); 064 } 065 066 private void send( 067 @Nonnull Email theEmail, @Nonnull Runnable theOnSuccess, @Nonnull Consumer<Throwable> theErrorHandler) { 068 Objects.requireNonNull(theEmail); 069 Objects.requireNonNull(theOnSuccess); 070 Objects.requireNonNull(theErrorHandler); 071 try { 072 myMailer.sendMail(theEmail, true).whenComplete((result, ex) -> { 073 if (ex != null) { 074 theErrorHandler.accept(ex); 075 } else { 076 theOnSuccess.run(); 077 } 078 }); 079 } catch (MailException e) { 080 theErrorHandler.accept(e); 081 } 082 } 083 084 @Nonnull 085 private Mailer makeMailer(@Nonnull MailConfig theMailConfig) { 086 ourLog.info( 087 "SMTP Mailer config Hostname:[{}] | Port:[{}] | Username:[{}] | TLS:[{}]", 088 theMailConfig.getSmtpHostname(), 089 theMailConfig.getSmtpPort(), 090 theMailConfig.getSmtpUsername(), 091 theMailConfig.isSmtpUseStartTLS()); 092 return MailerBuilder.withSMTPServer( 093 theMailConfig.getSmtpHostname(), 094 theMailConfig.getSmtpPort(), 095 theMailConfig.getSmtpUsername(), 096 theMailConfig.getSmtpPassword()) 097 .withTransportStrategy( 098 theMailConfig.isSmtpUseStartTLS() ? TransportStrategy.SMTP_TLS : TransportStrategy.SMTP) 099 .buildMailer(); 100 } 101 102 @Nonnull 103 private String makeMessage(@Nonnull Email theEmail) { 104 return " with subject [" + theEmail.getSubject() + "] and recipients [" 105 + theEmail.getRecipients().stream().map(Recipient::getAddress).collect(Collectors.joining(",")) + "]"; 106 } 107 108 private class OnSuccess implements Runnable { 109 private final Email myEmail; 110 111 private OnSuccess(@Nonnull Email theEmail) { 112 myEmail = theEmail; 113 } 114 115 @Override 116 public void run() { 117 ourLog.info("Email sent" + makeMessage(myEmail)); 118 } 119 } 120 121 private class ErrorHandler implements Consumer<Throwable> { 122 private final Email myEmail; 123 124 private ErrorHandler(@Nonnull Email theEmail) { 125 myEmail = theEmail; 126 } 127 128 @Override 129 public void accept(Throwable t) { 130 ourLog.error("Email not sent" + makeMessage(myEmail), t); 131 } 132 } 133}