001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.util.mail;
016    
017    import com.liferay.mail.model.FileAttachment;
018    import com.liferay.mail.service.MailServiceUtil;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.log.LogUtil;
024    import com.liferay.portal.kernel.mail.Account;
025    import com.liferay.portal.kernel.mail.MailMessage;
026    import com.liferay.portal.kernel.mail.SMTPAccount;
027    import com.liferay.portal.kernel.util.GetterUtil;
028    import com.liferay.portal.kernel.util.InfrastructureUtil;
029    import com.liferay.portal.kernel.util.Validator;
030    
031    import java.io.File;
032    
033    import java.net.SocketException;
034    
035    import java.util.Arrays;
036    import java.util.Date;
037    import java.util.List;
038    import java.util.Properties;
039    
040    import javax.activation.DataHandler;
041    import javax.activation.DataSource;
042    import javax.activation.FileDataSource;
043    
044    import javax.mail.Message;
045    import javax.mail.MessagingException;
046    import javax.mail.Part;
047    import javax.mail.SendFailedException;
048    import javax.mail.Session;
049    import javax.mail.Transport;
050    import javax.mail.internet.AddressException;
051    import javax.mail.internet.InternetAddress;
052    import javax.mail.internet.MimeBodyPart;
053    import javax.mail.internet.MimeMessage;
054    import javax.mail.internet.MimeMultipart;
055    
056    import org.apache.commons.lang.time.StopWatch;
057    
058    /**
059     * @author Brian Wing Shun Chan
060     * @author Brian Myunghun Kim
061     * @author Jorge Ferrer
062     * @author Neil Griffin
063     * @author Thiago Moreira
064     * @author Brett Swaim
065     */
066    public class MailEngine {
067    
068            public static Session getSession() {
069                    return getSession(false);
070            }
071    
072            public static Session getSession(Account account) {
073                    Properties properties = _getProperties(account);
074    
075                    Session session = Session.getInstance(properties);
076    
077                    if (_log.isDebugEnabled()) {
078                            session.setDebug(true);
079    
080                            session.getProperties().list(System.out);
081                    }
082    
083                    return session;
084            }
085    
086            public static Session getSession(boolean cache) {
087                    Session session = null;
088    
089                    try {
090                            session = MailServiceUtil.getSession();
091                    }
092                    catch (SystemException se) {
093                            if (_log.isWarnEnabled()) {
094                                    _log.warn(se, se);
095                            }
096    
097                            session = InfrastructureUtil.getMailSession();
098                    }
099    
100                    if (_log.isDebugEnabled()) {
101                            session.setDebug(true);
102    
103                            session.getProperties().list(System.out);
104                    }
105    
106                    return session;
107            }
108    
109            public static void send(byte[] bytes) throws MailEngineException {
110                    try {
111                            Session session = getSession();
112    
113                            Message message = new MimeMessage(
114                                    session, new UnsyncByteArrayInputStream(bytes));
115    
116                            _send(session, message, null);
117                    }
118                    catch (Exception e) {
119                            throw new MailEngineException(e);
120                    }
121            }
122    
123            public static void send(
124                            InternetAddress from, InternetAddress to, String subject,
125                            String body)
126                    throws MailEngineException {
127    
128                    send(
129                            from, new InternetAddress[] {to}, null, null, subject, body, false,
130                            null, null, null);
131            }
132    
133            public static void send(
134                            InternetAddress from, InternetAddress to, String subject,
135                            String body, boolean htmlFormat)
136                    throws MailEngineException {
137    
138                    send(
139                            from, new InternetAddress[] {to}, null, null, subject, body,
140                            htmlFormat, null, null, null);
141            }
142    
143            public static void send(
144                            InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
145                            InternetAddress[] bcc, InternetAddress[] bulkAddresses,
146                            String subject, String body, boolean htmlFormat,
147                            InternetAddress[] replyTo, String messageId, String inReplyTo)
148                    throws MailEngineException {
149    
150                    send(
151                            from, to, cc, bcc, bulkAddresses, subject, body, htmlFormat,
152                            replyTo, messageId, inReplyTo, null);
153            }
154    
155            public static void send(
156                            InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
157                            InternetAddress[] bcc, InternetAddress[] bulkAddresses,
158                            String subject, String body, boolean htmlFormat,
159                            InternetAddress[] replyTo, String messageId, String inReplyTo,
160                            List<FileAttachment> fileAttachments)
161                    throws MailEngineException {
162    
163                    send(
164                            from, to, cc, bcc, bulkAddresses, subject, body, htmlFormat,
165                            replyTo, messageId, inReplyTo, fileAttachments, null);
166            }
167    
168            public static void send(
169                            InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
170                            InternetAddress[] bcc, InternetAddress[] bulkAddresses,
171                            String subject, String body, boolean htmlFormat,
172                            InternetAddress[] replyTo, String messageId, String inReplyTo,
173                            List<FileAttachment> fileAttachments, SMTPAccount smtpAccount)
174                    throws MailEngineException {
175    
176                    StopWatch stopWatch = null;
177    
178                    if (_log.isDebugEnabled()) {
179                            stopWatch = new StopWatch();
180    
181                            stopWatch.start();
182    
183                            _log.debug("From: " + from);
184                            _log.debug("To: " + Arrays.toString(to));
185                            _log.debug("CC: " + Arrays.toString(cc));
186                            _log.debug("BCC: " + Arrays.toString(bcc));
187                            _log.debug("List Addresses: " + Arrays.toString(bulkAddresses));
188                            _log.debug("Subject: " + subject);
189                            _log.debug("Body: " + body);
190                            _log.debug("HTML Format: " + htmlFormat);
191                            _log.debug("Reply to: " + Arrays.toString(replyTo));
192                            _log.debug("Message ID: " + messageId);
193                            _log.debug("In Reply To: " + inReplyTo);
194    
195                            if ((fileAttachments != null) && _log.isDebugEnabled()) {
196                                    for (int i = 0; i < fileAttachments.size(); i++) {
197                                            FileAttachment fileAttachment = fileAttachments.get(i);
198    
199                                            File file = fileAttachment.getFile();
200    
201                                            if (file == null) {
202                                                    continue;
203                                            }
204    
205                                            _log.debug(
206                                                    "Attachment " + i + " file " + file.getAbsolutePath() +
207                                                            " and file name " + fileAttachment.getFileName());
208                                    }
209                            }
210                    }
211    
212                    try {
213                            Session session = null;
214    
215                            if (smtpAccount == null) {
216                                    session = getSession();
217                            }
218                            else {
219                                    session = getSession(smtpAccount);
220                            }
221    
222                            Message message = new LiferayMimeMessage(session);
223    
224                            message.setFrom(from);
225                            message.setRecipients(Message.RecipientType.TO, to);
226    
227                            if (cc != null) {
228                                    message.setRecipients(Message.RecipientType.CC, cc);
229                            }
230    
231                            if (bcc != null) {
232                                    message.setRecipients(Message.RecipientType.BCC, bcc);
233                            }
234    
235                            subject = GetterUtil.getString(subject);
236    
237                            message.setSubject(subject);
238    
239                            if ((fileAttachments != null) && (fileAttachments.size() > 0)) {
240                                    MimeMultipart rootMultipart = new MimeMultipart(
241                                            _MULTIPART_TYPE_MIXED);
242    
243                                    MimeMultipart messageMultipart = new MimeMultipart(
244                                            _MULTIPART_TYPE_ALTERNATIVE);
245    
246                                    MimeBodyPart messageBodyPart = new MimeBodyPart();
247    
248                                    messageBodyPart.setContent(messageMultipart);
249    
250                                    rootMultipart.addBodyPart(messageBodyPart);
251    
252                                    if (htmlFormat) {
253                                            MimeBodyPart bodyPart = new MimeBodyPart();
254    
255                                            bodyPart.setContent(body, _TEXT_HTML);
256    
257                                            messageMultipart.addBodyPart(bodyPart);
258                                    }
259                                    else {
260                                            MimeBodyPart bodyPart = new MimeBodyPart();
261    
262                                            bodyPart.setText(body);
263    
264                                            messageMultipart.addBodyPart(bodyPart);
265                                    }
266    
267                                    for (int i = 0; i < fileAttachments.size(); i++) {
268                                            FileAttachment fileAttachment = fileAttachments.get(i);
269    
270                                            File file = fileAttachment.getFile();
271    
272                                            if (file == null) {
273                                                    continue;
274                                            }
275    
276                                            MimeBodyPart mimeBodyPart = new MimeBodyPart();
277    
278                                            DataSource dataSource = new FileDataSource(file);
279    
280                                            mimeBodyPart.setDataHandler(new DataHandler(dataSource));
281                                            mimeBodyPart.setDisposition(Part.ATTACHMENT);
282    
283                                            if (fileAttachment.getFileName() != null) {
284                                                    mimeBodyPart.setFileName(fileAttachment.getFileName());
285                                            }
286                                            else {
287                                                    mimeBodyPart.setFileName(file.getName());
288                                            }
289    
290                                            rootMultipart.addBodyPart(mimeBodyPart);
291                                    }
292    
293                                    message.setContent(rootMultipart);
294    
295                                    message.saveChanges();
296                            }
297                            else {
298                                    if (htmlFormat) {
299                                            message.setContent(body, _TEXT_HTML);
300                                    }
301                                    else {
302                                            message.setContent(body, _TEXT_PLAIN);
303                                    }
304                            }
305    
306                            message.setSentDate(new Date());
307    
308                            if (replyTo != null) {
309                                    message.setReplyTo(replyTo);
310                            }
311    
312                            if (messageId != null) {
313                                    message.setHeader("Message-ID", messageId);
314                            }
315    
316                            if (inReplyTo != null) {
317                                    message.setHeader("In-Reply-To", inReplyTo);
318                                    message.setHeader("References", inReplyTo);
319                            }
320    
321                            _send(session, message, bulkAddresses);
322                    }
323                    catch (SendFailedException sfe) {
324                            _log.error(sfe);
325                    }
326                    catch (Exception e) {
327                            throw new MailEngineException(e);
328                    }
329    
330                    if (_log.isDebugEnabled()) {
331                            _log.debug("Sending mail takes " + stopWatch.getTime() + " ms");
332                    }
333            }
334    
335            public static void send(
336                            InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
337                            InternetAddress[] bcc, String subject, String body)
338                    throws MailEngineException {
339    
340                    send(from, to, cc, bcc, subject, body, false, null, null, null);
341            }
342    
343            public static void send(
344                            InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
345                            InternetAddress[] bcc, String subject, String body,
346                            boolean htmlFormat, InternetAddress[] replyTo, String messageId,
347                            String inReplyTo)
348                    throws MailEngineException {
349    
350                    send(
351                            from, to, cc, bcc, null, subject, body, htmlFormat, replyTo,
352                            messageId, inReplyTo, null);
353            }
354    
355            public static void send(
356                            InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
357                            String subject, String body)
358                    throws MailEngineException {
359    
360                    send(from, to, cc, null, subject, body, false, null, null, null);
361            }
362    
363            public static void send(
364                            InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
365                            String subject, String body, boolean htmlFormat)
366                    throws MailEngineException {
367    
368                    send(from, to, cc, null, subject, body, htmlFormat, null, null, null);
369            }
370    
371            public static void send(
372                            InternetAddress from, InternetAddress[] to, String subject,
373                            String body)
374                    throws MailEngineException {
375    
376                    send(from, to, null, null, subject, body, false, null, null, null);
377            }
378    
379            public static void send(
380                            InternetAddress from, InternetAddress[] to, String subject,
381                            String body, boolean htmlFormat)
382                    throws MailEngineException {
383    
384                    send(from, to, null, null, subject, body, htmlFormat, null, null, null);
385            }
386    
387            public static void send(MailMessage mailMessage)
388                    throws MailEngineException {
389    
390                    send(
391                            mailMessage.getFrom(), mailMessage.getTo(), mailMessage.getCC(),
392                            mailMessage.getBCC(), mailMessage.getBulkAddresses(),
393                            mailMessage.getSubject(), mailMessage.getBody(),
394                            mailMessage.isHTMLFormat(), mailMessage.getReplyTo(),
395                            mailMessage.getMessageId(), mailMessage.getInReplyTo(),
396                            mailMessage.getFileAttachments(), mailMessage.getSMTPAccount());
397            }
398    
399            public static void send(String from, String to, String subject, String body)
400                    throws MailEngineException {
401    
402                    try {
403                            send(
404                                    new InternetAddress(from), new InternetAddress(to), subject,
405                                    body);
406                    }
407                    catch (AddressException ae) {
408                            throw new MailEngineException(ae);
409                    }
410            }
411    
412            private static Properties _getProperties(Account account) {
413                    Properties properties = new Properties();
414    
415                    String protocol = account.getProtocol();
416    
417                    properties.setProperty("mail.transport.protocol", protocol);
418                    properties.setProperty("mail." + protocol + ".host", account.getHost());
419                    properties.setProperty(
420                            "mail." + protocol + ".port", String.valueOf(account.getPort()));
421    
422                    if (account.isRequiresAuthentication()) {
423                            properties.setProperty("mail." + protocol + ".auth", "true");
424                            properties.setProperty(
425                                    "mail." + protocol + ".user", account.getUser());
426                            properties.setProperty(
427                                    "mail." + protocol + ".password", account.getPassword());
428                    }
429    
430                    if (account.isSecure()) {
431                            properties.setProperty(
432                                    "mail." + protocol + ".socketFactory.class",
433                                    "javax.net.ssl.SSLSocketFactory");
434                            properties.setProperty(
435                                    "mail." + protocol + ".socketFactory.fallback", "false");
436                            properties.setProperty(
437                                    "mail." + protocol + ".socketFactory.port",
438                                    String.valueOf(account.getPort()));
439                    }
440    
441                    return properties;
442            }
443    
444            private static String _getSMTPProperty(Session session, String suffix) {
445                    String protocol = GetterUtil.getString(
446                            session.getProperty("mail.transport.protocol"));
447    
448                    if (protocol.equals(Account.PROTOCOL_SMTPS)) {
449                            return session.getProperty("mail.smtps." + suffix);
450                    }
451                    else {
452                            return session.getProperty("mail.smtp." + suffix);
453                    }
454            }
455    
456            private static void _send(
457                    Session session, Message message, InternetAddress[] bulkAddresses) {
458    
459                    try {
460                            boolean smtpAuth = GetterUtil.getBoolean(
461                                    _getSMTPProperty(session, "auth"), false);
462                            String smtpHost = _getSMTPProperty(session, "host");
463                            int smtpPort = GetterUtil.getInteger(
464                                    _getSMTPProperty(session, "port"), Account.PORT_SMTP);
465                            String user = _getSMTPProperty(session, "user");
466                            String password = _getSMTPProperty(session, "password");
467    
468                            if (smtpAuth && Validator.isNotNull(user) &&
469                                    Validator.isNotNull(password)) {
470    
471                                    String protocol = GetterUtil.getString(
472                                            session.getProperty("mail.transport.protocol"),
473                                            Account.PROTOCOL_SMTP);
474    
475                                    Transport transport = session.getTransport(protocol);
476    
477                                    transport.connect(smtpHost, smtpPort, user, password);
478    
479                                    if ((bulkAddresses != null) && (bulkAddresses.length > 0)) {
480                                            transport.sendMessage(message, bulkAddresses);
481                                    }
482                                    else {
483                                            transport.sendMessage(message, message.getAllRecipients());
484                                    }
485    
486                                    transport.close();
487                            }
488                            else {
489                                    if ((bulkAddresses != null) && (bulkAddresses.length > 0)) {
490                                            Transport.send(message, bulkAddresses);
491                                    }
492                                    else {
493                                            Transport.send(message);
494                                    }
495                            }
496                    }
497                    catch (MessagingException me) {
498                            if (me.getNextException() instanceof SocketException) {
499                                    if (_log.isWarnEnabled()) {
500                                            _log.warn(
501                                                    "Failed to connect to a valid mail server. Please " +
502                                                            "make sure one is properly configured. " +
503                                                                    me.getMessage());
504                                    }
505                            }
506                            else {
507                                    _log.error(me.getMessage());
508    
509                                    LogUtil.log(_log, me);
510                            }
511                    }
512            }
513    
514            private static final String _MULTIPART_TYPE_ALTERNATIVE = "alternative";
515    
516            private static final String _MULTIPART_TYPE_MIXED = "mixed";
517    
518            private static final String _TEXT_HTML = "text/html;charset=\"UTF-8\"";
519    
520            private static final String _TEXT_PLAIN = "text/plain;charset=\"UTF-8\"";
521    
522            private static Log _log = LogFactoryUtil.getLog(MailEngine.class);
523    
524    }