View Javadoc
1   /*
2    * Licensed to The Apereo Foundation under one or more contributor license
3    * agreements. See the NOTICE file distributed with this work for additional
4    * information regarding copyright ownership.
5    *
6    *
7    * The Apereo Foundation licenses this file to you under the Educational
8    * Community License, Version 2.0 (the "License"); you may not use this file
9    * except in compliance with the License. You may obtain a copy of the License
10   * at:
11   *
12   *   http://opensource.org/licenses/ecl2.txt
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
17   * License for the specific language governing permissions and limitations under
18   * the License.
19   *
20   */
21  
22  package org.opencastproject.kernel.mail;
23  
24  import org.apache.commons.lang3.StringUtils;
25  import org.slf4j.Logger;
26  import org.slf4j.LoggerFactory;
27  
28  import java.util.Date;
29  import java.util.Properties;
30  
31  import javax.mail.MessagingException;
32  import javax.mail.Session;
33  import javax.mail.Transport;
34  import javax.mail.internet.MimeMessage;
35  
36  /**
37   * Base implementation that allows to send e-mails using <code>javax.mail</code>.
38   */
39  public class BaseSmtpService {
40  
41    /** The logging facility */
42    private static final Logger logger = LoggerFactory.getLogger(BaseSmtpService.class);
43  
44    /** The mode */
45    protected enum Mode {
46      production, test
47    };
48  
49    /** Parameter prefix common to all "mail" properties */
50    protected static final String OPT_MAIL_PREFIX = "mail.";
51  
52    /** Parameter name for the transport protocol */
53    protected static final String OPT_MAIL_TRANSPORT = "mail.transport.protocol";
54  
55    /** Parameter suffix for the mail host */
56    protected static final String OPT_MAIL_HOST_SUFFIX = ".host";
57  
58    /** Parameter suffix for the mail port */
59    protected static final String OPT_MAIL_PORT_SUFFIX = ".port";
60  
61    /** Parameter suffix for the start tls status */
62    protected static final String OPT_MAIL_TLS_ENABLE_SUFFIX = ".starttls.enable";
63  
64    /** Parameter suffix for the authentication setting */
65    protected static final String OPT_MAIL_AUTH_SUFFIX = ".auth";
66  
67    /** Parameter name for the username */
68    protected static final String OPT_MAIL_USER = "mail.user";
69  
70    /** Parameter name for the password */
71    protected static final String OPT_MAIL_PASSWORD = "mail.password";
72  
73    /** Parameter name for the recipient */
74    protected static final String OPT_MAIL_FROM = "mail.from";
75  
76    /** Parameter name for the debugging setting */
77    protected static final String OPT_MAIL_DEBUG = "mail.debug";
78  
79    /** Default value for the transport protocol */
80    private static final String DEFAULT_MAIL_TRANSPORT = "smtp";
81  
82    /** Default value for the mail port */
83    private static final int DEFAULT_MAIL_PORT = 25;
84  
85    /** The current mail transport protocol */
86    protected String mailTransport = DEFAULT_MAIL_TRANSPORT;
87  
88    /** Flag indicating whether the service is actually sending messages */
89    private boolean productionMode = true;
90  
91    /** The mail host */
92    private String host = null;
93  
94    /** The mail port */
95    private int port = DEFAULT_MAIL_PORT;
96  
97    /** The mail user */
98    private String user = null;
99  
100   /** The mail password */
101   private String password = null;
102 
103   /** Whether debug is enabled */
104   private boolean debug = false;
105 
106   /** Whether SSL/TLS is enabled */
107   private boolean ssl = false;
108 
109   /** The optional sender */
110   private String sender = null;
111 
112   /** The mail properties */
113   private Properties mailProperties = new Properties();
114 
115   /** The default mail session */
116   private Session defaultMailSession = null;
117 
118   public void setProductionMode(boolean mode) {
119     this.productionMode = mode;
120   }
121 
122   public boolean isProductionMode() {
123     return productionMode;
124   }
125 
126   public void setHost(String host) {
127     this.host = host;
128   }
129 
130   public void setMailTransport(String mailTransport) {
131     this.mailTransport = mailTransport;
132   }
133 
134   public void setPort(Integer port) {
135     this.port = port;
136   }
137 
138   public void setUser(String user) {
139     this.user = user;
140   }
141 
142   public void setPassword(String password) {
143     this.password = password;
144   }
145 
146   public void setDebug(boolean debug) {
147     this.debug = debug;
148   }
149 
150   public void setSender(String sender) {
151     this.sender = sender;
152   }
153 
154   public String getSender() {
155     return this.sender;
156   }
157 
158   public void setSsl(boolean ssl) {
159     this.ssl = ssl;
160   }
161 
162   public void configure() {
163     mailProperties.clear();
164     defaultMailSession = null;
165 
166     if (!("smtp".equals(mailTransport) || "smtps".equals(mailTransport))) {
167       if (mailTransport != null) {
168         logger.warn("'{}' procotol not supported. Reverting to default: '{}'", mailTransport, DEFAULT_MAIL_TRANSPORT);
169       }
170       logger.debug("Mail transport protocol defaults to '{}'", DEFAULT_MAIL_TRANSPORT);
171       mailProperties.put(OPT_MAIL_TRANSPORT, DEFAULT_MAIL_TRANSPORT);
172     } else {
173       logger.debug("Mail transport protocol is '{}'", mailTransport);
174       mailProperties.put(OPT_MAIL_TRANSPORT, mailTransport);
175     }
176 
177     mailProperties.put(OPT_MAIL_PREFIX + mailTransport + OPT_MAIL_HOST_SUFFIX, host);
178     logger.debug("Mail host is {}", host);
179 
180     mailProperties.put(OPT_MAIL_PREFIX + mailTransport + OPT_MAIL_PORT_SUFFIX, port);
181     logger.debug("Mail server port is '{}'", port);
182 
183     // User and Authentication
184     String propName = OPT_MAIL_PREFIX + mailTransport + OPT_MAIL_AUTH_SUFFIX;
185     if (StringUtils.isNotBlank(user)) {
186       mailProperties.put(OPT_MAIL_USER, user);
187       mailProperties.put(propName, Boolean.toString(true));
188       logger.debug("Mail user is '{}'", user);
189     } else {
190       mailProperties.put(propName, Boolean.toString(false));
191       logger.debug("Sending mails to {} without authentication", host);
192     }
193 
194     if (StringUtils.isNotBlank(password)) {
195       mailProperties.put(OPT_MAIL_PASSWORD, password);
196       logger.debug("Mail password set");
197     }
198 
199     if (StringUtils.isNotBlank(sender)) {
200       mailProperties.put(OPT_MAIL_FROM, sender);
201       logger.debug("Mail sender is '{}'", sender);
202     } else {
203       logger.debug("Mail sender defaults not set");
204     }
205 
206     mailProperties.put(OPT_MAIL_PREFIX + mailTransport + OPT_MAIL_TLS_ENABLE_SUFFIX, ssl);
207     if (ssl) {
208       logger.debug("TLS over SMTP is enabled");
209     } else {
210       logger.debug("TLS over SMTP is disabled");
211     }
212 
213     mailProperties.put(OPT_MAIL_DEBUG, Boolean.toString(debug));
214     logger.debug("Mail debugging is {}", debug ? "enabled" : "disabled");
215 
216     logger.info("Mail service configured with {}", host);
217     Properties props = getSession().getProperties();
218     for (String key : props.stringPropertyNames()) {
219       logger.info("{}: {}", key, props.getProperty(key));
220     }
221   }
222 
223   /**
224    * Returns the default mail session that can be used to create a new message.
225    *
226    * @return the default mail session
227    */
228   public Session getSession() {
229     if (defaultMailSession == null) {
230       defaultMailSession = Session.getInstance(mailProperties);
231     }
232     return defaultMailSession;
233   }
234 
235   /**
236    * Creates a new message.
237    *
238    * @return the new message
239    */
240   public MimeMessage createMessage() {
241     return new MimeMessage(getSession());
242   }
243 
244   /**
245    * Sends <code>message</code> using the configured transport.
246    *
247    * @param message
248    *          the message
249    * @throws MessagingException
250    *           if sending the message failed
251    */
252   public void send(MimeMessage message) throws MessagingException {
253     message.setSentDate(new Date());
254     if (!productionMode) {
255       logger.debug("Skipping sending of message {} due to test mode", message);
256       return;
257     }
258     Transport t = getSession().getTransport(mailTransport);
259     ClassLoader cl = Thread.currentThread().getContextClassLoader();
260     try {
261       Thread.currentThread().setContextClassLoader(javax.mail.Session.class.getClassLoader());
262       if (user != null) {
263         t.connect(user, password);
264       } else {
265         t.connect();
266       }
267       t.sendMessage(message, message.getAllRecipients());
268     } finally {
269       Thread.currentThread().setContextClassLoader(cl);
270       t.close();
271     }
272   }
273 
274 }