001package ca.uhn.fhir.jpa.subscription.match.deliver.email;
002
003/*-
004 * #%L
005 * HAPI FHIR Subscription Server
006 * %%
007 * Copyright (C) 2014 - 2021 Smile CDR, Inc.
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 *
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import ca.uhn.fhir.rest.api.Constants;
024import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
025import ca.uhn.fhir.util.StopWatch;
026import org.apache.commons.lang3.StringUtils;
027import org.apache.commons.lang3.Validate;
028import org.slf4j.Logger;
029import org.slf4j.LoggerFactory;
030import org.springframework.mail.javamail.JavaMailSenderImpl;
031import org.thymeleaf.context.Context;
032import org.thymeleaf.spring5.SpringTemplateEngine;
033import org.thymeleaf.spring5.dialect.SpringStandardDialect;
034import org.thymeleaf.templatemode.TemplateMode;
035import org.thymeleaf.templateresolver.StringTemplateResolver;
036
037import javax.annotation.PostConstruct;
038import javax.mail.Message;
039import javax.mail.MessagingException;
040import javax.mail.internet.MimeMessage;
041import java.util.ArrayList;
042import java.util.Date;
043import java.util.List;
044import java.util.Properties;
045
046import static org.apache.commons.lang3.StringUtils.isNotBlank;
047import static org.apache.commons.lang3.StringUtils.trim;
048
049public class JavaMailEmailSender implements IEmailSender {
050
051        private static final Logger ourLog = LoggerFactory.getLogger(JavaMailEmailSender.class);
052        private String mySmtpServerHostname;
053        private int mySmtpServerPort = 25;
054        private JavaMailSenderImpl mySender;
055        private String mySmtpServerUsername;
056        private String mySmtpServerPassword;
057        private final Properties myJavaMailProperties = new Properties();
058
059        public String getSmtpServerHostname() {
060                return mySmtpServerHostname;
061        }
062
063        /**
064         * Set the SMTP server host to use for outbound mail
065         */
066        public void setSmtpServerHostname(String theSmtpServerHostname) {
067                mySmtpServerHostname = theSmtpServerHostname;
068        }
069
070        public String getSmtpServerPassword() {
071                return mySmtpServerPassword;
072        }
073
074        public void setSmtpServerPassword(String theSmtpServerPassword) {
075                mySmtpServerPassword = theSmtpServerPassword;
076        }
077
078        public int getSmtpServerPort() {
079                return mySmtpServerPort;
080        }
081
082        /**
083         * Set the SMTP server port to use for outbound mail
084         */
085        public void setSmtpServerPort(int theSmtpServerPort) {
086                mySmtpServerPort = theSmtpServerPort;
087        }
088
089        public String getSmtpServerUsername() {
090                return mySmtpServerUsername;
091        }
092
093        public void setSmtpServerUsername(String theSmtpServerUsername) {
094                mySmtpServerUsername = theSmtpServerUsername;
095        }
096
097        /**
098         * Set the "mail.smtp.auth" Java Mail Property
099         */
100
101        public void setAuth(Boolean theAuth) {
102                myJavaMailProperties.setProperty("mail.smtp.auth", theAuth.toString());
103        }
104
105        /**
106         * Set the "mail.smtp.starttls.enable" Java Mail Property
107         */
108
109        public void setStartTlsEnable(Boolean theStartTlsEnable) {
110                myJavaMailProperties.setProperty("mail.smtp.starttls.enable", theStartTlsEnable.toString());
111        }
112
113        /**
114         * Set the "mail.smtp.starttls.required" Java Mail Property
115         */
116
117        public void setStartTlsRequired(Boolean theStartTlsRequired) {
118                myJavaMailProperties.setProperty("mail.smtp.starttls.required", theStartTlsRequired.toString());
119        }
120
121        /**
122         * Set the "mail.smtp.quitwait" Java Mail Property
123         */
124
125        public void setQuitWait(Boolean theQuitWait) {
126                myJavaMailProperties.setProperty("mail.smtp.quitwait", theQuitWait.toString());
127        }
128
129        @Override
130        public void send(EmailDetails theDetails) {
131                String subscriptionId = theDetails.getSubscription().toUnqualifiedVersionless().getValue();
132                StopWatch sw = new StopWatch();
133
134                StringTemplateResolver templateResolver = new StringTemplateResolver();
135                templateResolver.setTemplateMode(TemplateMode.TEXT);
136
137                SpringStandardDialect dialect = new SpringStandardDialect();
138                dialect.setEnableSpringELCompiler(true);
139
140                SpringTemplateEngine engine = new SpringTemplateEngine();
141                engine.setDialect(dialect);
142                engine.setEnableSpringELCompiler(true);
143                engine.setTemplateResolver(templateResolver);
144
145                Context context = new Context();
146
147                String body = engine.process(theDetails.getBodyTemplate(), context);
148                String subject = engine.process(theDetails.getSubjectTemplate(), context);
149
150                MimeMessage email = mySender.createMimeMessage();
151
152                String from = trim(theDetails.getFrom());
153                ourLog.info("Sending email for subscription {} from [{}] to recipients: [{}]", subscriptionId, from, theDetails.getTo());
154
155                try {
156                        email.setFrom(from);
157                        email.setRecipients(Message.RecipientType.TO, toTrimmedCommaSeparatedString(theDetails.getTo()));
158                        email.setSubject(subject);
159                        email.setText(body);
160                        email.setSentDate(new Date());
161                        email.addHeader("X-FHIR-Subscription", subscriptionId);
162                } catch (MessagingException e) {
163                        throw new InternalErrorException("Failed to create email message", e);
164                }
165
166                mySender.send(email);
167
168                ourLog.info("Done sending email (took {}ms)", sw.getMillis());
169        }
170
171        @PostConstruct
172        public void start() {
173                Validate.notBlank(mySmtpServerHostname, "No SMTP host defined");
174
175                mySender = new JavaMailSenderImpl();
176                mySender.setHost(getSmtpServerHostname());
177                mySender.setPort(getSmtpServerPort());
178                mySender.setUsername(getSmtpServerUsername());
179                mySender.setPassword(getSmtpServerPassword());
180                mySender.setDefaultEncoding(Constants.CHARSET_UTF8.name());
181                mySender.setJavaMailProperties(myJavaMailProperties);
182        }
183
184        private static String toTrimmedCommaSeparatedString(List<String> theTo) {
185                List<String> to = new ArrayList<>();
186                for (String next : theTo) {
187                        if (isNotBlank(next)) {
188                                to.add(next);
189                        }
190                }
191
192                return StringUtils.join(to, ",");
193        }
194}