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