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