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