1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.util.mail;
24  
25  import com.liferay.mail.service.MailServiceUtil;
26  import com.liferay.portal.SystemException;
27  import com.liferay.portal.kernel.log.Log;
28  import com.liferay.portal.kernel.log.LogFactoryUtil;
29  import com.liferay.portal.kernel.mail.Account;
30  import com.liferay.portal.kernel.mail.MailMessage;
31  import com.liferay.portal.kernel.mail.SMTPAccount;
32  import com.liferay.portal.kernel.util.GetterUtil;
33  import com.liferay.portal.kernel.util.InfrastructureUtil;
34  import com.liferay.portal.kernel.util.Validator;
35  
36  import java.io.ByteArrayInputStream;
37  import java.io.File;
38  
39  import java.net.SocketException;
40  
41  import java.util.Date;
42  import java.util.Properties;
43  
44  import javax.activation.DataHandler;
45  import javax.activation.DataSource;
46  import javax.activation.FileDataSource;
47  
48  import javax.mail.Message;
49  import javax.mail.MessagingException;
50  import javax.mail.Part;
51  import javax.mail.SendFailedException;
52  import javax.mail.Session;
53  import javax.mail.Transport;
54  import javax.mail.internet.AddressException;
55  import javax.mail.internet.InternetAddress;
56  import javax.mail.internet.MimeBodyPart;
57  import javax.mail.internet.MimeMessage;
58  import javax.mail.internet.MimeMultipart;
59  
60  import org.apache.commons.lang.time.StopWatch;
61  
62  /**
63   * <a href="MailEngine.java.html"><b><i>View Source</i></b></a>
64   *
65   * @author Brian Wing Shun Chan
66   * @author Brian Myunghun Kim
67   * @author Jorge Ferrer
68   * @author Neil Griffin
69   * @author Thiago Moreira
70   * @author Brett Swaim
71   */
72  public class MailEngine {
73  
74      public static Session getSession() {
75          return getSession(false);
76      }
77  
78      public static Session getSession(boolean cache) {
79          Session session = null;
80  
81          try {
82              session = MailServiceUtil.getSession();
83          }
84          catch (SystemException se) {
85              if (_log.isWarnEnabled()) {
86                  _log.warn(se, se);
87              }
88  
89              session = InfrastructureUtil.getMailSession();
90          }
91  
92          if (_log.isDebugEnabled()) {
93              session.setDebug(true);
94  
95              session.getProperties().list(System.out);
96          }
97  
98          return session;
99      }
100 
101     public static Session getSession(Account account) {
102         Properties properties = _getProperties(account);
103 
104         Session session = Session.getInstance(properties);
105 
106         if (_log.isDebugEnabled()) {
107             session.setDebug(true);
108 
109             session.getProperties().list(System.out);
110         }
111 
112         return session;
113     }
114 
115     public static void send(MailMessage mailMessage)
116         throws MailEngineException {
117 
118         send(
119             mailMessage.getFrom(), mailMessage.getTo(), mailMessage.getCC(),
120             mailMessage.getBCC(), mailMessage.getBulkAddresses(),
121             mailMessage.getSubject(), mailMessage.getBody(),
122             mailMessage.isHTMLFormat(), mailMessage.getReplyTo(),
123             mailMessage.getMessageId(), mailMessage.getInReplyTo(),
124             mailMessage.getAttachments(), mailMessage.getSMTPAccount());
125     }
126 
127     public static void send(String from, String to, String subject, String body)
128         throws MailEngineException {
129 
130         try {
131             send(
132                 new InternetAddress(from), new InternetAddress(to), subject,
133                 body);
134         }
135         catch (AddressException ae) {
136             throw new MailEngineException(ae);
137         }
138     }
139 
140     public static void send(
141             InternetAddress from, InternetAddress to,
142             String subject, String body)
143         throws MailEngineException {
144 
145         send(
146             from, new InternetAddress[] {to}, null, null, subject, body, false,
147             null, null, null);
148     }
149 
150     public static void send(
151             InternetAddress from, InternetAddress to, String subject,
152             String body, boolean htmlFormat)
153         throws MailEngineException {
154 
155         send(
156             from, new InternetAddress[] {to}, null, null, subject, body,
157             htmlFormat, null, null, null);
158     }
159 
160     public static void send(
161             InternetAddress from, InternetAddress[] to, String subject,
162             String body)
163         throws MailEngineException {
164 
165         send(from, to, null, null, subject, body, false, null, null, null);
166     }
167 
168     public static void send(
169             InternetAddress from, InternetAddress[] to, String subject,
170             String body, boolean htmlFormat)
171         throws MailEngineException {
172 
173         send(from, to, null, null, subject, body, htmlFormat, null, null, null);
174     }
175 
176     public static void send(
177             InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
178             String subject, String body)
179         throws MailEngineException {
180 
181         send(from, to, cc, null, subject, body, false, null, null, null);
182     }
183 
184     public static void send(
185             InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
186             String subject, String body, boolean htmlFormat)
187         throws MailEngineException {
188 
189         send(from, to, cc, null, subject, body, htmlFormat, null, null, null);
190     }
191 
192     public static void send(
193             InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
194             InternetAddress[] bcc, String subject, String body)
195         throws MailEngineException {
196 
197         send(from, to, cc, bcc, subject, body, false, null, null, null);
198     }
199 
200     public static void send(
201             InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
202             InternetAddress[] bcc, String subject, String body,
203             boolean htmlFormat, InternetAddress[] replyTo, String messageId,
204             String inReplyTo)
205         throws MailEngineException {
206 
207         send(
208             from, to, cc, bcc, null, subject, body, htmlFormat, replyTo,
209             messageId, inReplyTo, null);
210     }
211 
212     public static void send(
213             InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
214             InternetAddress[] bcc, InternetAddress[] bulkAddresses,
215             String subject, String body, boolean htmlFormat,
216             InternetAddress[] replyTo, String messageId, String inReplyTo)
217         throws MailEngineException {
218 
219         send(
220             from, to, cc, bcc, bulkAddresses, subject, body, htmlFormat,
221             replyTo, messageId, inReplyTo, null);
222     }
223 
224     public static void send(
225             InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
226             InternetAddress[] bcc, InternetAddress[] bulkAddresses,
227             String subject, String body, boolean htmlFormat,
228             InternetAddress[] replyTo, String messageId, String inReplyTo,
229             File[] attachments)
230         throws MailEngineException {
231 
232         send(
233             from, to, cc, bcc, bulkAddresses, subject, body, htmlFormat,
234             replyTo, messageId, inReplyTo, attachments, null);
235     }
236 
237     public static void send(
238             InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
239             InternetAddress[] bcc, InternetAddress[] bulkAddresses,
240             String subject, String body, boolean htmlFormat,
241             InternetAddress[] replyTo, String messageId, String inReplyTo,
242             File[] attachments, SMTPAccount smtpAccount)
243         throws MailEngineException {
244 
245         StopWatch stopWatch = null;
246 
247         if (_log.isDebugEnabled()) {
248             stopWatch = new StopWatch();
249 
250             stopWatch.start();
251 
252             _log.debug("From: " + from);
253             _log.debug("To: " + to);
254             _log.debug("CC: " + cc);
255             _log.debug("BCC: " + bcc);
256             _log.debug("List Addresses: " + bulkAddresses);
257             _log.debug("Subject: " + subject);
258             _log.debug("Body: " + body);
259             _log.debug("HTML Format: " + htmlFormat);
260             _log.debug("Reply to: " + replyTo);
261             _log.debug("Message ID: " + messageId);
262             _log.debug("In Reply To: " + inReplyTo);
263 
264             if (attachments != null) {
265                 for (int i = 0; i < attachments.length; i++) {
266                     File attachment = attachments[i];
267 
268                     if (attachment != null) {
269                         String path = attachment.getAbsolutePath();
270 
271                         _log.debug("Attachment #" + (i + 1) + ": " + path);
272                     }
273                 }
274             }
275         }
276 
277         try {
278             Session session = null;
279 
280             if (smtpAccount == null) {
281                 session = getSession();
282             }
283             else {
284                 session = getSession(smtpAccount);
285             }
286 
287             Message msg = new LiferayMimeMessage(session);
288 
289             msg.setFrom(from);
290             msg.setRecipients(Message.RecipientType.TO, to);
291 
292             if (cc != null) {
293                 msg.setRecipients(Message.RecipientType.CC, cc);
294             }
295 
296             if (bcc != null) {
297                 msg.setRecipients(Message.RecipientType.BCC, bcc);
298             }
299 
300             msg.setSubject(subject);
301 
302             if ((attachments != null) && (attachments.length > 0)) {
303                 MimeMultipart rootMultipart = new MimeMultipart(
304                     _MULTIPART_TYPE_MIXED);
305 
306                 MimeMultipart messageMultipart = new MimeMultipart(
307                     _MULTIPART_TYPE_ALTERNATIVE);
308 
309                 MimeBodyPart messageBodyPart = new MimeBodyPart();
310 
311                 messageBodyPart.setContent(messageMultipart);
312 
313                 rootMultipart.addBodyPart(messageBodyPart);
314 
315                 if (htmlFormat) {
316                     MimeBodyPart bodyPart = new MimeBodyPart();
317 
318                     bodyPart.setContent(body, _TEXT_HTML);
319 
320                     messageMultipart.addBodyPart(bodyPart);
321                 }
322                 else {
323                     MimeBodyPart bodyPart = new MimeBodyPart();
324 
325                     bodyPart.setText(body);
326 
327                     messageMultipart.addBodyPart(bodyPart);
328                 }
329 
330                 for (int i = 0; i < attachments.length; i++) {
331                     File attachment = attachments[i];
332 
333                     if (attachment != null) {
334                         MimeBodyPart bodyPart = new MimeBodyPart();
335 
336                         DataSource source = new FileDataSource(attachment);
337 
338                         bodyPart.setDisposition(Part.ATTACHMENT);
339                         bodyPart.setDataHandler(new DataHandler(source));
340                         bodyPart.setFileName(attachment.getName());
341 
342                         rootMultipart.addBodyPart(bodyPart);
343                     }
344                 }
345 
346                 msg.setContent(rootMultipart);
347 
348                 msg.saveChanges();
349             }
350             else {
351                 if (htmlFormat) {
352                     msg.setContent(body, _TEXT_HTML);
353                 }
354                 else {
355                     msg.setContent(body, _TEXT_PLAIN);
356                 }
357             }
358 
359             msg.setSentDate(new Date());
360 
361             if (replyTo != null) {
362                 msg.setReplyTo(replyTo);
363             }
364 
365             if (messageId != null) {
366                 msg.setHeader("Message-ID", messageId);
367             }
368 
369             if (inReplyTo != null) {
370                 msg.setHeader("In-Reply-To", inReplyTo);
371                 msg.setHeader("References", inReplyTo);
372             }
373 
374             _send(session, msg, bulkAddresses);
375         }
376         catch (SendFailedException sfe) {
377             _log.error(sfe);
378         }
379         catch (Exception e) {
380             throw new MailEngineException(e);
381         }
382 
383         if (_log.isDebugEnabled()) {
384             _log.debug("Sending mail takes " + stopWatch.getTime() + " ms");
385         }
386     }
387 
388     public static void send(byte[] msgByteArray) throws MailEngineException {
389         try {
390             Session session = getSession();
391 
392             Message msg = new MimeMessage(
393                 session, new ByteArrayInputStream(msgByteArray));
394 
395             _send(session, msg, null);
396         }
397         catch (Exception e) {
398             throw new MailEngineException(e);
399         }
400     }
401 
402     private static Properties _getProperties(Account account) {
403         Properties properties = new Properties();
404 
405         String protocol = account.getProtocol();
406 
407         properties.setProperty("mail.transport.protocol", protocol);
408         properties.setProperty("mail." + protocol + ".host", account.getHost());
409         properties.setProperty(
410             "mail." + protocol + ".port", String.valueOf(account.getPort()));
411 
412         if (account.isRequiresAuthentication()) {
413             properties.setProperty("mail." + protocol + ".auth", "true");
414             properties.setProperty(
415                 "mail." + protocol + ".user", account.getUser());
416             properties.setProperty(
417                 "mail." + protocol + ".password", account.getPassword());
418         }
419 
420         if (account.isSecure()) {
421             properties.setProperty(
422                 "mail." + protocol + ".socketFactory.class",
423                 "javax.net.ssl.SSLSocketFactory");
424             properties.setProperty(
425                 "mail." + protocol + ".socketFactory.fallback", "false");
426             properties.setProperty(
427                 "mail." + protocol + ".socketFactory.port",
428                 String.valueOf(account.getPort()));
429         }
430 
431         return properties;
432     }
433 
434     private static String _getSMTPProperty(Session session, String suffix) {
435         String protocol = GetterUtil.getString(
436             session.getProperty("mail.transport.protocol"));
437 
438         if (protocol.equals(Account.PROTOCOL_SMTPS)) {
439             return session.getProperty("mail.smtps." + suffix);
440         }
441         else {
442             return session.getProperty("mail.smtp." + suffix);
443         }
444     }
445 
446     private static void _send(
447         Session session, Message msg, InternetAddress[] bulkAddresses) {
448 
449         try {
450             boolean smtpAuth = GetterUtil.getBoolean(
451                 _getSMTPProperty(session, "auth"), false);
452             String smtpHost = _getSMTPProperty(session, "host");
453             int smtpPort = GetterUtil.getInteger(
454                 _getSMTPProperty(session, "port"), Account.PORT_SMTP);
455             String user = _getSMTPProperty(session, "user");
456             String password = _getSMTPProperty(session, "password");
457 
458             if (smtpAuth && Validator.isNotNull(user) &&
459                 Validator.isNotNull(password)) {
460 
461                 String protocol = GetterUtil.getString(
462                     session.getProperty("mail.transport.protocol"),
463                     Account.PROTOCOL_SMTP);
464 
465                 Transport transport = session.getTransport(protocol);
466 
467                 transport.connect(smtpHost, smtpPort, user, password);
468 
469                 if ((bulkAddresses != null) && (bulkAddresses.length > 0)) {
470                     transport.sendMessage(msg, bulkAddresses);
471                 }
472                 else {
473                     transport.sendMessage(msg, msg.getAllRecipients());
474                 }
475 
476                 transport.close();
477             }
478             else {
479                 if ((bulkAddresses != null) && (bulkAddresses.length > 0)) {
480                     Transport.send(msg, bulkAddresses);
481                 }
482                 else {
483                     Transport.send(msg);
484                 }
485             }
486         }
487         catch (MessagingException me) {
488             if (me.getNextException() instanceof SocketException) {
489                 if (_log.isWarnEnabled()) {
490                     _log.warn(
491                         "Failed to connect to a valid mail server. Please " +
492                             "make sure one is properly configured. " +
493                                 me.getMessage());
494                 }
495             }
496         }
497     }
498 
499     private static final String _MULTIPART_TYPE_ALTERNATIVE = "alternative";
500 
501     private static final String _MULTIPART_TYPE_MIXED = "mixed";
502 
503     private static final String _TEXT_HTML = "text/html;charset=\"UTF-8\"";
504 
505     private static final String _TEXT_PLAIN = "text/plain;charset=\"UTF-8\"";
506 
507     private static Log _log = LogFactoryUtil.getLog(MailEngine.class);
508 
509 }