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