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       logger.debug("Mail transport protocol defaults to '{}'", DEFAULT_MAIL_TRANSPORT);
170       mailProperties.put(OPT_MAIL_TRANSPORT, DEFAULT_MAIL_TRANSPORT);
171     } else {
172       logger.debug("Mail transport protocol is '{}'", mailTransport);
173       mailProperties.put(OPT_MAIL_TRANSPORT, mailTransport);
174     }
175 
176     mailProperties.put(OPT_MAIL_PREFIX + mailTransport + OPT_MAIL_HOST_SUFFIX, host);
177     logger.debug("Mail host is {}", host);
178 
179     mailProperties.put(OPT_MAIL_PREFIX + mailTransport + OPT_MAIL_PORT_SUFFIX, port);
180     logger.debug("Mail server port is '{}'", port);
181 
182     // User and Authentication
183     String propName = OPT_MAIL_PREFIX + mailTransport + OPT_MAIL_AUTH_SUFFIX;
184     if (StringUtils.isNotBlank(user)) {
185       mailProperties.put(OPT_MAIL_USER, user);
186       mailProperties.put(propName, Boolean.toString(true));
187       logger.debug("Mail user is '{}'", user);
188     } else {
189       mailProperties.put(propName, Boolean.toString(false));
190       logger.debug("Sending mails to {} without authentication", host);
191     }
192 
193     if (StringUtils.isNotBlank(password)) {
194       mailProperties.put(OPT_MAIL_PASSWORD, password);
195       logger.debug("Mail password set");
196     }
197 
198     if (StringUtils.isNotBlank(sender)) {
199       mailProperties.put(OPT_MAIL_FROM, sender);
200       logger.debug("Mail sender is '{}'", sender);
201     } else {
202       logger.debug("Mail sender defaults not set");
203     }
204 
205     mailProperties.put(OPT_MAIL_PREFIX + mailTransport + OPT_MAIL_TLS_ENABLE_SUFFIX, ssl);
206     if (ssl) {
207       logger.debug("TLS over SMTP is enabled");
208     } else {
209       logger.debug("TLS over SMTP is disabled");
210     }
211 
212     mailProperties.put(OPT_MAIL_DEBUG, Boolean.toString(debug));
213     logger.debug("Mail debugging is {}", debug ? "enabled" : "disabled");
214 
215     logger.info("Mail service configured with {}", host);
216     Properties props = getSession().getProperties();
217     for (String key : props.stringPropertyNames())
218       logger.info("{}: {}", key, props.getProperty(key));
219   }
220 
221   /**
222    * Returns the default mail session that can be used to create a new message.
223    *
224    * @return the default mail session
225    */
226   public Session getSession() {
227     if (defaultMailSession == null) {
228       defaultMailSession = Session.getInstance(mailProperties);
229     }
230     return defaultMailSession;
231   }
232 
233   /**
234    * Creates a new message.
235    *
236    * @return the new message
237    */
238   public MimeMessage createMessage() {
239     return new MimeMessage(getSession());
240   }
241 
242   /**
243    * Sends <code>message</code> using the configured transport.
244    *
245    * @param message
246    *          the message
247    * @throws MessagingException
248    *           if sending the message failed
249    */
250   public void send(MimeMessage message) throws MessagingException {
251     message.setSentDate(new Date());
252     if (!productionMode) {
253       logger.debug("Skipping sending of message {} due to test mode", message);
254       return;
255     }
256     Transport t = getSession().getTransport(mailTransport);
257     ClassLoader cl = Thread.currentThread().getContextClassLoader();
258     try {
259       Thread.currentThread().setContextClassLoader(javax.mail.Session.class.getClassLoader());
260       if (user != null)
261         t.connect(user, password);
262       else
263         t.connect();
264       t.sendMessage(message, message.getAllRecipients());
265     } finally {
266       Thread.currentThread().setContextClassLoader(cl);
267       t.close();
268     }
269   }
270 
271 }