001package ca.uhn.fhir.jpa.subscription.module.subscriber.email;
002
003/*-
004 * #%L
005 * HAPI FHIR Subscription Server
006 * %%
007 * Copyright (C) 2014 - 2020 University Health Network
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;
044
045import static org.apache.commons.lang3.StringUtils.isNotBlank;
046import static org.apache.commons.lang3.StringUtils.trim;
047
048public class JavaMailEmailSender implements IEmailSender {
049
050        private static final Logger ourLog = LoggerFactory.getLogger(JavaMailEmailSender.class);
051        private String mySmtpServerHostname;
052        private int mySmtpServerPort = 25;
053        private JavaMailSenderImpl mySender;
054        private String mySmtpServerUsername;
055        private String mySmtpServerPassword;
056
057        public String getSmtpServerHostname() {
058                return mySmtpServerHostname;
059        }
060
061        /**
062         * Set the SMTP server host to use for outbound mail
063         */
064        public void setSmtpServerHostname(String theSmtpServerHostname) {
065                mySmtpServerHostname = theSmtpServerHostname;
066        }
067
068        public String getSmtpServerPassword() {
069                return mySmtpServerPassword;
070        }
071
072        public void setSmtpServerPassword(String theSmtpServerPassword) {
073                mySmtpServerPassword = theSmtpServerPassword;
074        }
075
076        public int getSmtpServerPort() {
077                return mySmtpServerPort;
078        }
079
080        /**
081         * Set the SMTP server port to use for outbound mail
082         */
083        public void setSmtpServerPort(int theSmtpServerPort) {
084                mySmtpServerPort = theSmtpServerPort;
085        }
086
087        public String getSmtpServerUsername() {
088                return mySmtpServerUsername;
089        }
090
091        public void setSmtpServerUsername(String theSmtpServerUsername) {
092                mySmtpServerUsername = theSmtpServerUsername;
093        }
094
095        @Override
096        public void send(EmailDetails theDetails) {
097                String subscriptionId = theDetails.getSubscription().toUnqualifiedVersionless().getValue();
098                StopWatch sw = new StopWatch();
099
100                StringTemplateResolver templateResolver = new StringTemplateResolver();
101                templateResolver.setTemplateMode(TemplateMode.TEXT);
102
103                SpringStandardDialect dialect = new SpringStandardDialect();
104                dialect.setEnableSpringELCompiler(true);
105
106                SpringTemplateEngine engine = new SpringTemplateEngine();
107                engine.setDialect(dialect);
108                engine.setEnableSpringELCompiler(true);
109                engine.setTemplateResolver(templateResolver);
110
111                Context context = new Context();
112
113                String body = engine.process(theDetails.getBodyTemplate(), context);
114                String subject = engine.process(theDetails.getSubjectTemplate(), context);
115
116                MimeMessage email = mySender.createMimeMessage();
117
118                String from = trim(theDetails.getFrom());
119                ourLog.info("Sending email for subscription {} from [{}] to recipients: [{}]", subscriptionId, from, theDetails.getTo());
120
121                try {
122                        email.setFrom(from);
123                        email.setRecipients(Message.RecipientType.TO, toTrimmedCommaSeparatedString(theDetails.getTo()));
124                        email.setSubject(subject);
125                        email.setText(body);
126                        email.setSentDate(new Date());
127                        email.addHeader("X-FHIR-Subscription", subscriptionId);
128                } catch (MessagingException e) {
129                        throw new InternalErrorException("Failed to create email message", e);
130                }
131
132                mySender.send(email);
133
134                ourLog.info("Done sending email (took {}ms)", sw.getMillis());
135        }
136
137        @PostConstruct
138        public void start() {
139                Validate.notBlank(mySmtpServerHostname, "No SMTP host defined");
140
141                mySender = new JavaMailSenderImpl();
142                mySender.setHost(getSmtpServerHostname());
143                mySender.setPort(getSmtpServerPort());
144                mySender.setUsername(getSmtpServerUsername());
145                mySender.setPassword(getSmtpServerPassword());
146                mySender.setDefaultEncoding(Constants.CHARSET_UTF8.name());
147        }
148
149        private static String toTrimmedCommaSeparatedString(List<String> theTo) {
150                List<String> to = new ArrayList<>();
151                for (String next : theTo) {
152                        if (isNotBlank(next)) {
153                                to.add(next);
154                        }
155                }
156
157                return StringUtils.join(to, ",");
158        }
159}