001    /**
002     * Copyright (c) 2000-2010 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.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(boolean cache) {
071                    Session session = null;
072    
073                    try {
074                            session = MailServiceUtil.getSession();
075                    }
076                    catch (SystemException se) {
077                            if (_log.isWarnEnabled()) {
078                                    _log.warn(se, se);
079                            }
080    
081                            session = InfrastructureUtil.getMailSession();
082                    }
083    
084                    if (_log.isDebugEnabled()) {
085                            session.setDebug(true);
086    
087                            session.getProperties().list(System.out);
088                    }
089    
090                    return session;
091            }
092    
093            public static Session getSession(Account account) {
094                    Properties properties = _getProperties(account);
095    
096                    Session session = Session.getInstance(properties);
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(MailMessage mailMessage)
108                    throws MailEngineException {
109    
110                    send(
111                            mailMessage.getFrom(), mailMessage.getTo(), mailMessage.getCC(),
112                            mailMessage.getBCC(), mailMessage.getBulkAddresses(),
113                            mailMessage.getSubject(), mailMessage.getBody(),
114                            mailMessage.isHTMLFormat(), mailMessage.getReplyTo(),
115                            mailMessage.getMessageId(), mailMessage.getInReplyTo(),
116                            mailMessage.getAttachments(), mailMessage.getSMTPAccount());
117            }
118    
119            public static void send(String from, String to, String subject, String body)
120                    throws MailEngineException {
121    
122                    try {
123                            send(
124                                    new InternetAddress(from), new InternetAddress(to), subject,
125                                    body);
126                    }
127                    catch (AddressException ae) {
128                            throw new MailEngineException(ae);
129                    }
130            }
131    
132            public static void send(
133                            InternetAddress from, InternetAddress to,
134                            String subject, String body)
135                    throws MailEngineException {
136    
137                    send(
138                            from, new InternetAddress[] {to}, null, null, subject, body, false,
139                            null, null, null);
140            }
141    
142            public static void send(
143                            InternetAddress from, InternetAddress to, String subject,
144                            String body, boolean htmlFormat)
145                    throws MailEngineException {
146    
147                    send(
148                            from, new InternetAddress[] {to}, null, null, subject, body,
149                            htmlFormat, null, null, null);
150            }
151    
152            public static void send(
153                            InternetAddress from, InternetAddress[] to, String subject,
154                            String body)
155                    throws MailEngineException {
156    
157                    send(from, to, null, null, subject, body, false, null, null, null);
158            }
159    
160            public static void send(
161                            InternetAddress from, InternetAddress[] to, String subject,
162                            String body, boolean htmlFormat)
163                    throws MailEngineException {
164    
165                    send(from, to, null, null, subject, body, htmlFormat, null, null, null);
166            }
167    
168            public static void send(
169                            InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
170                            String subject, String body)
171                    throws MailEngineException {
172    
173                    send(from, to, cc, null, subject, body, false, null, null, null);
174            }
175    
176            public static void send(
177                            InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
178                            String subject, String body, boolean htmlFormat)
179                    throws MailEngineException {
180    
181                    send(from, to, cc, null, subject, body, htmlFormat, null, null, null);
182            }
183    
184            public static void send(
185                            InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
186                            InternetAddress[] bcc, String subject, String body)
187                    throws MailEngineException {
188    
189                    send(from, to, cc, bcc, subject, body, false, 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                            boolean htmlFormat, InternetAddress[] replyTo, String messageId,
196                            String inReplyTo)
197                    throws MailEngineException {
198    
199                    send(
200                            from, to, cc, bcc, null, subject, body, htmlFormat, replyTo,
201                            messageId, inReplyTo, null);
202            }
203    
204            public static void send(
205                            InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
206                            InternetAddress[] bcc, InternetAddress[] bulkAddresses,
207                            String subject, String body, boolean htmlFormat,
208                            InternetAddress[] replyTo, String messageId, String inReplyTo)
209                    throws MailEngineException {
210    
211                    send(
212                            from, to, cc, bcc, bulkAddresses, subject, body, htmlFormat,
213                            replyTo, messageId, inReplyTo, null);
214            }
215    
216            public static void send(
217                            InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
218                            InternetAddress[] bcc, InternetAddress[] bulkAddresses,
219                            String subject, String body, boolean htmlFormat,
220                            InternetAddress[] replyTo, String messageId, String inReplyTo,
221                            File[] attachments)
222                    throws MailEngineException {
223    
224                    send(
225                            from, to, cc, bcc, bulkAddresses, subject, body, htmlFormat,
226                            replyTo, messageId, inReplyTo, attachments, null);
227            }
228    
229            public static void send(
230                            InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
231                            InternetAddress[] bcc, InternetAddress[] bulkAddresses,
232                            String subject, String body, boolean htmlFormat,
233                            InternetAddress[] replyTo, String messageId, String inReplyTo,
234                            File[] attachments, SMTPAccount smtpAccount)
235                    throws MailEngineException {
236    
237                    StopWatch stopWatch = null;
238    
239                    if (_log.isDebugEnabled()) {
240                            stopWatch = new StopWatch();
241    
242                            stopWatch.start();
243    
244                            _log.debug("From: " + from);
245                            _log.debug("To: " + Arrays.toString(to));
246                            _log.debug("CC: " + Arrays.toString(cc));
247                            _log.debug("BCC: " + Arrays.toString(bcc));
248                            _log.debug("List Addresses: " + Arrays.toString(bulkAddresses));
249                            _log.debug("Subject: " + subject);
250                            _log.debug("Body: " + body);
251                            _log.debug("HTML Format: " + htmlFormat);
252                            _log.debug("Reply to: " + Arrays.toString(replyTo));
253                            _log.debug("Message ID: " + messageId);
254                            _log.debug("In Reply To: " + inReplyTo);
255    
256                            if (attachments != null) {
257                                    for (int i = 0; i < attachments.length; i++) {
258                                            File attachment = attachments[i];
259    
260                                            if (attachment != null) {
261                                                    String path = attachment.getAbsolutePath();
262    
263                                                    _log.debug("Attachment #" + (i + 1) + ": " + path);
264                                            }
265                                    }
266                            }
267                    }
268    
269                    try {
270                            Session session = null;
271    
272                            if (smtpAccount == null) {
273                                    session = getSession();
274                            }
275                            else {
276                                    session = getSession(smtpAccount);
277                            }
278    
279                            Message msg = new LiferayMimeMessage(session);
280    
281                            msg.setFrom(from);
282                            msg.setRecipients(Message.RecipientType.TO, to);
283    
284                            if (cc != null) {
285                                    msg.setRecipients(Message.RecipientType.CC, cc);
286                            }
287    
288                            if (bcc != null) {
289                                    msg.setRecipients(Message.RecipientType.BCC, bcc);
290                            }
291    
292                            msg.setSubject(subject);
293    
294                            if ((attachments != null) && (attachments.length > 0)) {
295                                    MimeMultipart rootMultipart = new MimeMultipart(
296                                            _MULTIPART_TYPE_MIXED);
297    
298                                    MimeMultipart messageMultipart = new MimeMultipart(
299                                            _MULTIPART_TYPE_ALTERNATIVE);
300    
301                                    MimeBodyPart messageBodyPart = new MimeBodyPart();
302    
303                                    messageBodyPart.setContent(messageMultipart);
304    
305                                    rootMultipart.addBodyPart(messageBodyPart);
306    
307                                    if (htmlFormat) {
308                                            MimeBodyPart bodyPart = new MimeBodyPart();
309    
310                                            bodyPart.setContent(body, _TEXT_HTML);
311    
312                                            messageMultipart.addBodyPart(bodyPart);
313                                    }
314                                    else {
315                                            MimeBodyPart bodyPart = new MimeBodyPart();
316    
317                                            bodyPart.setText(body);
318    
319                                            messageMultipart.addBodyPart(bodyPart);
320                                    }
321    
322                                    for (int i = 0; i < attachments.length; i++) {
323                                            File attachment = attachments[i];
324    
325                                            if (attachment != null) {
326                                                    MimeBodyPart bodyPart = new MimeBodyPart();
327    
328                                                    DataSource source = new FileDataSource(attachment);
329    
330                                                    bodyPart.setDisposition(Part.ATTACHMENT);
331                                                    bodyPart.setDataHandler(new DataHandler(source));
332                                                    bodyPart.setFileName(attachment.getName());
333    
334                                                    rootMultipart.addBodyPart(bodyPart);
335                                            }
336                                    }
337    
338                                    msg.setContent(rootMultipart);
339    
340                                    msg.saveChanges();
341                            }
342                            else {
343                                    if (htmlFormat) {
344                                            msg.setContent(body, _TEXT_HTML);
345                                    }
346                                    else {
347                                            msg.setContent(body, _TEXT_PLAIN);
348                                    }
349                            }
350    
351                            msg.setSentDate(new Date());
352    
353                            if (replyTo != null) {
354                                    msg.setReplyTo(replyTo);
355                            }
356    
357                            if (messageId != null) {
358                                    msg.setHeader("Message-ID", messageId);
359                            }
360    
361                            if (inReplyTo != null) {
362                                    msg.setHeader("In-Reply-To", inReplyTo);
363                                    msg.setHeader("References", inReplyTo);
364                            }
365    
366                            _send(session, msg, bulkAddresses);
367                    }
368                    catch (SendFailedException sfe) {
369                            _log.error(sfe);
370                    }
371                    catch (Exception e) {
372                            throw new MailEngineException(e);
373                    }
374    
375                    if (_log.isDebugEnabled()) {
376                            _log.debug("Sending mail takes " + stopWatch.getTime() + " ms");
377                    }
378            }
379    
380            public static void send(byte[] msgByteArray) throws MailEngineException {
381                    try {
382                            Session session = getSession();
383    
384                            Message msg = new MimeMessage(
385                                    session, new UnsyncByteArrayInputStream(msgByteArray));
386    
387                            _send(session, msg, null);
388                    }
389                    catch (Exception e) {
390                            throw new MailEngineException(e);
391                    }
392            }
393    
394            private static Properties _getProperties(Account account) {
395                    Properties properties = new Properties();
396    
397                    String protocol = account.getProtocol();
398    
399                    properties.setProperty("mail.transport.protocol", protocol);
400                    properties.setProperty("mail." + protocol + ".host", account.getHost());
401                    properties.setProperty(
402                            "mail." + protocol + ".port", String.valueOf(account.getPort()));
403    
404                    if (account.isRequiresAuthentication()) {
405                            properties.setProperty("mail." + protocol + ".auth", "true");
406                            properties.setProperty(
407                                    "mail." + protocol + ".user", account.getUser());
408                            properties.setProperty(
409                                    "mail." + protocol + ".password", account.getPassword());
410                    }
411    
412                    if (account.isSecure()) {
413                            properties.setProperty(
414                                    "mail." + protocol + ".socketFactory.class",
415                                    "javax.net.ssl.SSLSocketFactory");
416                            properties.setProperty(
417                                    "mail." + protocol + ".socketFactory.fallback", "false");
418                            properties.setProperty(
419                                    "mail." + protocol + ".socketFactory.port",
420                                    String.valueOf(account.getPort()));
421                    }
422    
423                    return properties;
424            }
425    
426            private static String _getSMTPProperty(Session session, String suffix) {
427                    String protocol = GetterUtil.getString(
428                            session.getProperty("mail.transport.protocol"));
429    
430                    if (protocol.equals(Account.PROTOCOL_SMTPS)) {
431                            return session.getProperty("mail.smtps." + suffix);
432                    }
433                    else {
434                            return session.getProperty("mail.smtp." + suffix);
435                    }
436            }
437    
438            private static void _send(
439                    Session session, Message msg, InternetAddress[] bulkAddresses) {
440    
441                    try {
442                            boolean smtpAuth = GetterUtil.getBoolean(
443                                    _getSMTPProperty(session, "auth"), false);
444                            String smtpHost = _getSMTPProperty(session, "host");
445                            int smtpPort = GetterUtil.getInteger(
446                                    _getSMTPProperty(session, "port"), Account.PORT_SMTP);
447                            String user = _getSMTPProperty(session, "user");
448                            String password = _getSMTPProperty(session, "password");
449    
450                            if (smtpAuth && Validator.isNotNull(user) &&
451                                    Validator.isNotNull(password)) {
452    
453                                    String protocol = GetterUtil.getString(
454                                            session.getProperty("mail.transport.protocol"),
455                                            Account.PROTOCOL_SMTP);
456    
457                                    Transport transport = session.getTransport(protocol);
458    
459                                    transport.connect(smtpHost, smtpPort, user, password);
460    
461                                    if ((bulkAddresses != null) && (bulkAddresses.length > 0)) {
462                                            transport.sendMessage(msg, bulkAddresses);
463                                    }
464                                    else {
465                                            transport.sendMessage(msg, msg.getAllRecipients());
466                                    }
467    
468                                    transport.close();
469                            }
470                            else {
471                                    if ((bulkAddresses != null) && (bulkAddresses.length > 0)) {
472                                            Transport.send(msg, bulkAddresses);
473                                    }
474                                    else {
475                                            Transport.send(msg);
476                                    }
477                            }
478                    }
479                    catch (MessagingException me) {
480                            if (me.getNextException() instanceof SocketException) {
481                                    if (_log.isWarnEnabled()) {
482                                            _log.warn(
483                                                    "Failed to connect to a valid mail server. Please " +
484                                                            "make sure one is properly configured. " +
485                                                                    me.getMessage());
486                                    }
487                            }
488                            else {
489                                    _log.error(me.getMessage());
490    
491                                    LogUtil.log(_log, me);
492                            }
493                    }
494            }
495    
496            private static final String _MULTIPART_TYPE_ALTERNATIVE = "alternative";
497    
498            private static final String _MULTIPART_TYPE_MIXED = "mixed";
499    
500            private static final String _TEXT_HTML = "text/html;charset=\"UTF-8\"";
501    
502            private static final String _TEXT_PLAIN = "text/plain;charset=\"UTF-8\"";
503    
504            private static Log _log = LogFactoryUtil.getLog(MailEngine.class);
505    
506    }