View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.mail;
18  
19  import static org.junit.Assert.assertEquals;
20  import static org.junit.Assert.assertFalse;
21  import static org.junit.Assert.assertNotNull;
22  import static org.junit.Assert.assertTrue;
23  import static org.junit.Assert.fail;
24  
25  import java.io.File;
26  import java.io.IOException;
27  import java.net.URL;
28  import java.util.List;
29  
30  import javax.activation.DataSource;
31  import javax.activation.FileDataSource;
32  import javax.mail.internet.MimeMessage;
33  
34  import org.apache.commons.mail.mocks.MockHtmlEmailConcrete;
35  import org.apache.commons.mail.settings.EmailConfiguration;
36  import org.apache.commons.mail.util.MimeMessageParser;
37  import org.junit.Before;
38  import org.junit.Ignore;
39  import org.junit.Test;
40  import org.junit.runner.RunWith;
41  import org.powermock.core.classloader.annotations.PrepareForTest;
42  import org.powermock.modules.junit4.PowerMockRunner;
43  
44  /**
45   * JUnit test case for HtmlEmail Class.
46   *
47   * @since 1.0
48   * @version $Id: HtmlEmailTest.java 1647983 2014-12-26 14:25:27Z tn $
49   */
50  @RunWith(PowerMockRunner.class)
51  @PrepareForTest( { MockHtmlEmailConcrete.class })
52  public class HtmlEmailTest extends AbstractEmailTest
53  {
54      private MockHtmlEmailConcrete email;
55  
56      @Before
57      public void setUpHtmlEmailTest()
58      {
59          // reusable objects to be used across multiple tests
60          this.email = new MockHtmlEmailConcrete();
61      }
62  
63      @Test
64      public void testGetSetTextMsg() throws EmailException
65      {
66          // ====================================================================
67          // Test Success
68          // ====================================================================
69          for (final String validChar : testCharsValid)
70          {
71              this.email.setTextMsg(validChar);
72              assertEquals(validChar, this.email.getTextMsg());
73          }
74  
75          // ====================================================================
76          // Test Exception
77          // ====================================================================
78          for (final String invalidChar : this.testCharsNotValid)
79          {
80              try
81              {
82                  this.email.setTextMsg(invalidChar);
83                  fail("Should have thrown an exception");
84              }
85              catch (final EmailException e)
86              {
87                  assertTrue(true);
88              }
89          }
90  
91      }
92  
93      @Test
94      public void testGetSetHtmlMsg() throws EmailException
95      {
96          // ====================================================================
97          // Test Success
98          // ====================================================================
99          for (final String validChar : testCharsValid)
100         {
101             this.email.setHtmlMsg(validChar);
102             assertEquals(validChar, this.email.getHtmlMsg());
103         }
104 
105         // ====================================================================
106         // Test Exception
107         // ====================================================================
108         for (final String invalidChar : this.testCharsNotValid)
109         {
110             try
111             {
112                 this.email.setHtmlMsg(invalidChar);
113                 fail("Should have thrown an exception");
114             }
115             catch (final EmailException e)
116             {
117                 assertTrue(true);
118             }
119         }
120 
121     }
122 
123     @Test
124     public void testGetSetMsg() throws EmailException
125     {
126         // ====================================================================
127         // Test Success
128         // ====================================================================
129         for (final String validChar : testCharsValid)
130         {
131             this.email.setMsg(validChar);
132             assertEquals(validChar, this.email.getTextMsg());
133 
134             assertTrue(
135                     this.email.getHtmlMsg().contains(validChar));
136         }
137 
138         // ====================================================================
139         // Test Exception
140         // ====================================================================
141         for (final String invalidChar : this.testCharsNotValid)
142         {
143             try
144             {
145                 this.email.setMsg(invalidChar);
146                 fail("Should have thrown an exception");
147             }
148             catch (final EmailException e)
149             {
150                 assertTrue(true);
151             }
152         }
153 
154     }
155 
156     @Test
157     public void testEmbedUrl() throws Exception
158     {
159         // ====================================================================
160         // Test Success
161         // ====================================================================
162 
163         final String strEmbed =
164             this.email.embed(new URL(this.strTestURL), "Test name");
165         assertNotNull(strEmbed);
166         assertEquals(HtmlEmail.CID_LENGTH, strEmbed.length());
167 
168         // if we embed the same name again, do we get the same content ID
169         // back?
170         final String testCid =
171             this.email.embed(new URL(this.strTestURL), "Test name");
172         assertEquals(strEmbed, testCid);
173 
174         // if we embed the same URL under a different name, is the content ID
175         // unique?
176         final String newCid =
177             this.email.embed(new URL(this.strTestURL), "Test name 2");
178         assertFalse(strEmbed.equals(newCid));
179 
180         // ====================================================================
181         // Test Exceptions
182         // ====================================================================
183 
184         // Does an invalid URL throw an exception?
185         try
186         {
187             this.email.embed(createInvalidURL(), "Bad URL");
188             fail("Should have thrown an exception");
189         }
190         catch (final EmailException e)
191         {
192             // expected
193         }
194 
195         // if we try to embed a different URL under a previously used name,
196         // does it complain?
197         try
198         {
199             this.email.embed(new URL("http://www.google.com"), "Test name");
200             fail("shouldn't be able to use an existing name with a different URL!");
201         }
202         catch (final EmailException e)
203         {
204             // expected
205         }
206     }
207 
208     @Test
209     public void testEmbedFile() throws Exception
210     {
211         // ====================================================================
212         // Test Success
213         // ====================================================================
214 
215         final File file = File.createTempFile("testEmbedFile", "txt");
216         file.deleteOnExit();
217         final String strEmbed = this.email.embed(file);
218         assertNotNull(strEmbed);
219         assertEquals("generated CID has wrong length",
220                 HtmlEmail.CID_LENGTH, strEmbed.length());
221 
222         // if we embed the same file again, do we get the same content ID
223         // back?
224         final String testCid =
225             this.email.embed(file);
226         assertEquals("didn't get same CID after embedding same file twice",
227                 strEmbed, testCid);
228 
229         // if we embed a new file, is the content ID unique?
230         final File otherFile = File.createTempFile("testEmbedFile2", "txt");
231         otherFile.deleteOnExit();
232         final String newCid = this.email.embed(otherFile);
233         assertFalse("didn't get unique CID from embedding new file",
234                 strEmbed.equals(newCid));
235     }
236 
237     @Test
238     public void testEmbedUrlAndFile() throws Exception
239     {
240         final File tmpFile = File.createTempFile("testfile", "txt");
241         tmpFile.deleteOnExit();
242         final String fileCid = this.email.embed(tmpFile);
243 
244         final URL fileUrl = tmpFile.toURI().toURL();
245         final String urlCid = this.email.embed(fileUrl, "urlName");
246 
247         assertFalse("file and URL cids should be different even for same resource",
248                 fileCid.equals(urlCid));
249     }
250 
251     @Test
252     public void testEmbedDataSource() throws Exception
253     {
254         final File tmpFile = File.createTempFile("testEmbedDataSource", "txt");
255         tmpFile.deleteOnExit();
256         final FileDataSource dataSource = new FileDataSource(tmpFile);
257 
258         // does embedding a datasource without a name fail?
259         try
260         {
261             this.email.embed(dataSource, "");
262             fail("embedding with an empty string for a name should fail");
263         }
264         catch (final EmailException e)
265         {
266             // expected
267         }
268 
269         // properly embed the datasource
270         final String cid = this.email.embed(dataSource, "testname");
271 
272         // does embedding the same datasource under the same name return
273         // the original cid?
274         final String sameCid = this.email.embed(dataSource, "testname");
275         assertEquals("didn't get same CID for embedding same datasource twice",
276                 cid, sameCid);
277 
278         // does embedding another datasource under the same name fail?
279         final File anotherFile = File.createTempFile("testEmbedDataSource2", "txt");
280         anotherFile.deleteOnExit();
281         final FileDataSource anotherDS = new FileDataSource(anotherFile);
282         try
283         {
284             this.email.embed(anotherDS, "testname");
285         }
286         catch (final EmailException e)
287         {
288             // expected
289         }
290     }
291 
292     /**
293      * @throws EmailException when bad addresses and attachments are used
294      * @throws IOException if creating a temp file, URL or sending fails
295      */
296     @Test
297     public void testSend() throws EmailException, IOException
298     {
299         final EmailAttachment attachment = new EmailAttachment();
300         File testFile = null;
301 
302         /** File to used to test file attachments (Must be valid) */
303         testFile = File.createTempFile("commons-email-testfile", ".txt");
304         testFile.deleteOnExit();
305 
306         // ====================================================================
307         // Test Success
308         // ====================================================================
309         this.getMailServer();
310 
311         String strSubject = "Test HTML Send #1 Subject (w charset)";
312 
313         this.email = new MockHtmlEmailConcrete();
314         this.email.setHostName(this.strTestMailServer);
315         this.email.setSmtpPort(this.getMailServerPort());
316         this.email.setFrom(this.strTestMailFrom);
317         this.email.addTo(this.strTestMailTo);
318 
319         /** File to used to test file attachmetns (Must be valid) */
320         attachment.setName("Test Attachment");
321         attachment.setDescription("Test Attachment Desc");
322         attachment.setPath(testFile.getAbsolutePath());
323         this.email.attach(attachment);
324 
325         //this.email.setAuthentication(this.strTestUser, this.strTestPasswd);
326 
327         this.email.setCharset(EmailConstants.ISO_8859_1);
328         this.email.setSubject(strSubject);
329 
330         final URL url = new URL(EmailConfiguration.TEST_URL);
331         final String cid = this.email.embed(url, "Apache Logo");
332 
333         final String strHtmlMsg =
334             "<html>The Apache logo - <img src=\"cid:" + cid + "\"><html>";
335 
336         this.email.setHtmlMsg(strHtmlMsg);
337         this.email.setTextMsg(
338             "Your email client does not support HTML emails");
339 
340         this.email.send();
341         this.fakeMailServer.stop();
342         // validate txt message
343         validateSend(
344             this.fakeMailServer,
345             strSubject,
346             this.email.getTextMsg(),
347             this.email.getFromAddress(),
348             this.email.getToAddresses(),
349             this.email.getCcAddresses(),
350             this.email.getBccAddresses(),
351             true);
352 
353         // validate html message
354         validateSend(
355             this.fakeMailServer,
356             strSubject,
357             this.email.getHtmlMsg(),
358             this.email.getFromAddress(),
359             this.email.getToAddresses(),
360             this.email.getCcAddresses(),
361             this.email.getBccAddresses(),
362             false);
363 
364         // validate attachment
365         validateSend(
366             this.fakeMailServer,
367             strSubject,
368             attachment.getName(),
369             this.email.getFromAddress(),
370             this.email.getToAddresses(),
371             this.email.getCcAddresses(),
372             this.email.getBccAddresses(),
373             false);
374 
375         this.getMailServer();
376 
377         this.email = new MockHtmlEmailConcrete();
378         this.email.setHostName(this.strTestMailServer);
379         this.email.setSmtpPort(this.getMailServerPort());
380         this.email.setFrom(this.strTestMailFrom);
381         this.email.addTo(this.strTestMailTo);
382 
383         if (this.strTestUser != null && this.strTestPasswd != null)
384         {
385             this.email.setAuthentication(
386                 this.strTestUser,
387                 this.strTestPasswd);
388         }
389 
390         strSubject = "Test HTML Send #1 Subject (wo charset)";
391         this.email.setSubject(strSubject);
392         this.email.setTextMsg("Test message");
393 
394         this.email.send();
395         this.fakeMailServer.stop();
396         // validate txt message
397         validateSend(
398             this.fakeMailServer,
399             strSubject,
400             this.email.getTextMsg(),
401             this.email.getFromAddress(),
402             this.email.getToAddresses(),
403             this.email.getCcAddresses(),
404             this.email.getBccAddresses(),
405             true);
406     }
407 
408     @Test
409     public void testSend2() throws Exception
410     {
411         // ====================================================================
412         // Test Success
413         // ====================================================================
414 
415         this.getMailServer();
416 
417         this.email = new MockHtmlEmailConcrete();
418         this.email.setHostName(this.strTestMailServer);
419         this.email.setSmtpPort(this.getMailServerPort());
420         this.email.setFrom(this.strTestMailFrom);
421         this.email.addTo(this.strTestMailTo);
422 
423         if (this.strTestUser != null && this.strTestPasswd != null)
424         {
425             this.email.setAuthentication(
426                 this.strTestUser,
427                 this.strTestPasswd);
428         }
429 
430         String strSubject = "Test HTML Send #2 Subject (wo charset)";
431         this.email.setSubject(strSubject);
432         this.email.setMsg("Test txt msg");
433 
434         this.email.send();
435         this.fakeMailServer.stop();
436         // validate txt message
437         validateSend(
438             this.fakeMailServer,
439             strSubject,
440             this.email.getTextMsg(),
441             this.email.getFromAddress(),
442             this.email.getToAddresses(),
443             this.email.getCcAddresses(),
444             this.email.getBccAddresses(),
445             true);
446 
447         // validate html message
448         validateSend(
449             this.fakeMailServer,
450             strSubject,
451             this.email.getHtmlMsg(),
452             this.email.getFromAddress(),
453             this.email.getToAddresses(),
454             this.email.getCcAddresses(),
455             this.email.getBccAddresses(),
456             false);
457 
458         this.getMailServer();
459 
460         this.email = new MockHtmlEmailConcrete();
461         this.email.setHostName(this.strTestMailServer);
462         this.email.setFrom(this.strTestMailFrom);
463         this.email.setSmtpPort(this.getMailServerPort());
464         this.email.addTo(this.strTestMailTo);
465 
466         if (this.strTestUser != null && this.strTestPasswd != null)
467         {
468             this.email.setAuthentication(
469                 this.strTestUser,
470                 this.strTestPasswd);
471         }
472 
473         strSubject = "Test HTML Send #2 Subject (w charset)";
474         this.email.setCharset(EmailConstants.ISO_8859_1);
475         this.email.setSubject(strSubject);
476         this.email.setMsg("Test txt msg");
477 
478         this.email.send();
479         this.fakeMailServer.stop();
480         // validate txt message
481         validateSend(
482             this.fakeMailServer,
483             strSubject,
484             this.email.getTextMsg(),
485             this.email.getFromAddress(),
486             this.email.getToAddresses(),
487             this.email.getCcAddresses(),
488             this.email.getBccAddresses(),
489             true);
490 
491         // validate html message
492         validateSend(
493             this.fakeMailServer,
494             strSubject,
495             this.email.getHtmlMsg(),
496             this.email.getFromAddress(),
497             this.email.getToAddresses(),
498             this.email.getCcAddresses(),
499             this.email.getBccAddresses(),
500             false);
501 
502     }
503 
504     @Test
505     @Ignore
506     public void testSendWithDefaultCharset() throws Exception
507     {
508         // Test is disabled as its result is dependent on the execution order:
509         // the mail.mime.charset property is normally cached by the MimeUtility
510         // class, thus setting it to another value while running the tests
511         // might not have the expected result.
512 
513         // ====================================================================
514         // Test Success
515         // ====================================================================
516 
517         System.setProperty(EmailConstants.MAIL_MIME_CHARSET, "iso-8859-15");
518 
519         this.getMailServer();
520 
521         this.email = new MockHtmlEmailConcrete();
522         this.email.setHostName(this.strTestMailServer);
523         this.email.setSmtpPort(this.getMailServerPort());
524         this.email.setFrom(this.strTestMailFrom);
525         this.email.addTo(this.strTestMailTo);
526 
527         if (this.strTestUser != null && this.strTestPasswd != null)
528         {
529             this.email.setAuthentication(
530                 this.strTestUser,
531                 this.strTestPasswd);
532         }
533 
534         final String strSubject = "Test HTML Send Subject (w default charset)";
535         this.email.setSubject(strSubject);
536         this.email.setMsg("Test txt msg รค"); // add non-ascii character, otherwise us-ascii will be used
537 
538         this.email.send();
539         this.fakeMailServer.stop();
540         // validate charset
541         validateSend(
542             this.fakeMailServer,
543             strSubject,
544             "charset=iso-8859-15",
545             this.email.getFromAddress(),
546             this.email.getToAddresses(),
547             this.email.getCcAddresses(),
548             this.email.getBccAddresses(),
549             true);
550 
551         System.clearProperty(EmailConstants.MAIL_MIME_CHARSET);
552 
553     }
554 
555     /**
556      * Create a HTML email containing an URL pointing to a ZIP file
557      * to be downloaded. According to EMAIL-93 the resulting URL
558      * "http://paradisedelivery.homeip.net/delivery/?file=TZC268X93337..zip"
559      * contains TWO dots instead of one dot which breaks the link.
560      */
561     @Test
562     public void testAddZipUrl() throws Exception
563     {
564         final String htmlMsg =
565                 "Please click on the following link: <br><br>" +
566                 "<a href=\"http://paradisedelivery.homeip.net/delivery/?file=3DTZC268X93337.zip\">" +
567                 "http://paradisedelivery.homeip.net/delivery/?file=3DTZC268X93337.zip" +
568                 "</a><br><br>Customer satisfaction is very important for us.";
569 
570         this.getMailServer();
571 
572         this.email = new MockHtmlEmailConcrete();
573         this.email.setHostName(this.strTestMailServer);
574         this.email.setSmtpPort(this.getMailServerPort());
575         this.email.setFrom(this.strTestMailFrom);
576         this.email.addTo(this.strTestMailTo);
577         this.email.setCharset(EmailConstants.ISO_8859_1);
578 
579         if (this.strTestUser != null && this.strTestPasswd != null)
580         {
581             this.email.setAuthentication(
582                 this.strTestUser,
583                 this.strTestPasswd);
584         }
585 
586         final String strSubject = "A dot (\".\") is appended to some ULRs of a HTML mail.";
587         this.email.setSubject(strSubject);
588         this.email.setHtmlMsg(htmlMsg);
589 
590         this.email.send();
591         this.fakeMailServer.stop();
592 
593         // validate html message
594         validateSend(
595             this.fakeMailServer,
596             strSubject,
597             this.email.getHtmlMsg(),
598             this.email.getFromAddress(),
599             this.email.getToAddresses(),
600             this.email.getCcAddresses(),
601             this.email.getBccAddresses(),
602             false);
603         
604         // make sure that no double dots show up
605         assertTrue(this.email.getHtmlMsg().contains("3DTZC268X93337.zip"));
606         assertFalse(this.email.getHtmlMsg().contains("3DTZC268X93337..zip"));
607     }
608 
609     /**
610      * According to EMAIL-95 calling buildMimeMessage() before calling send()
611      * causes duplicate mime parts - now we throw an exception to catch the
612      * problem
613      */
614     @Test
615     public void testCallingBuildMimeMessageBeforeSent() throws Exception {
616 
617         final String htmlMsg = "<b>Hello World</b>";
618 
619         this.email = new MockHtmlEmailConcrete();
620         this.email.setHostName(this.strTestMailServer);
621         this.email.setSmtpPort(this.getMailServerPort());
622         this.email.setFrom(this.strTestMailFrom);
623         this.email.addTo(this.strTestMailTo);
624         this.email.setCharset(EmailConstants.ISO_8859_1);
625 
626         if (this.strTestUser != null && this.strTestPasswd != null)
627         {
628             this.email.setAuthentication(
629                 this.strTestUser,
630                 this.strTestPasswd);
631         }
632 
633         final String strSubject = "testCallingBuildMimeMessageBeforeSent";
634         this.email.setSubject(strSubject);
635         this.email.setHtmlMsg(htmlMsg);
636 
637         // this should NOT be called when sending a message
638         this.email.buildMimeMessage();
639 
640         try
641         {
642             this.email.send();
643         }
644         catch(final IllegalStateException e)
645         {
646             return;
647         }
648 
649         fail("Expecting an exception when calling buildMimeMessage() before send() ...");
650     }
651 
652     /**
653      * EMAIL-73 - check that providing a plain text content using setMsg()
654      * creates a plain content and HTML content using {@code <pre>} tags.
655      */
656     @Test
657     public void testSendWithPlainTextButNoHtmlContent() throws EmailException, IOException
658     {
659         this.getMailServer();
660 
661         final String strSubject = "testSendWithPlainTextButNoHtmlContent";
662 
663         this.email = new MockHtmlEmailConcrete();
664         this.email.setHostName(this.strTestMailServer);
665         this.email.setSmtpPort(this.getMailServerPort());
666         this.email.setFrom(this.strTestMailFrom);
667         this.email.addTo(this.strTestMailTo);
668         this.email.setAuthentication(this.strTestUser, this.strTestPasswd);
669         this.email.setCharset(EmailConstants.ISO_8859_1);
670         this.email.setSubject(strSubject);
671         this.email.setMsg("This is a plain text content : <b><&npsb;></html></b>");
672 
673         this.email.send();
674 
675         this.fakeMailServer.stop();
676 
677         // validate text message
678         validateSend(
679             this.fakeMailServer,
680             strSubject,
681             this.email.getTextMsg(),
682             this.email.getFromAddress(),
683             this.email.getToAddresses(),
684             this.email.getCcAddresses(),
685             this.email.getBccAddresses(),
686             true);
687     }
688 
689     /**
690      * Test that the specified Content-ID is used when embedding a File
691      * object in an HtmlEmail.
692      *
693      * Rolled back the changes since they broke real emails therefore
694      * the test is currently disabled.
695      *
696      * see https://issues.apache.org/jira/browse/EMAIL-101
697      */
698     @Test
699     public void testEmbedFileWithCID() throws Exception
700     {
701          // ====================================================================
702          // Test Success
703          // ====================================================================
704 
705          final File file = File.createTempFile("testEmbedFile", "txt");
706          file.deleteOnExit();
707 
708          final String testCid = "Test CID";
709          final String encodedCid = EmailUtils.encodeUrl(testCid);
710 
711          // if we embed a new file, do we get the content ID we specified back?
712          final String strEmbed = this.email.embed(file, testCid);
713          assertNotNull(strEmbed);
714          assertEquals("didn't get same CID when embedding with a specified CID", encodedCid, strEmbed);
715 
716          // if we embed the same file again, do we get the same content ID
717          // back?
718          final String returnedCid = this.email.embed(file);
719          assertEquals("didn't get same CID after embedding same file twice", encodedCid, returnedCid);
720     }
721 
722     @Test
723     public void testHtmlMailMimeLayout() throws Exception
724     {
725         assertCorrectContentType("contentTypeTest.gif", "image/gif");
726         assertCorrectContentType("contentTypeTest.jpg", "image/jpeg");
727         assertCorrectContentType("contentTypeTest.png", "image/png");
728     }
729 
730     private void assertCorrectContentType(final String picture, final String contentType) throws Exception {
731         final HtmlEmail htmlEmail = createDefaultHtmlEmail();
732         final String cid = htmlEmail.embed(new File("./src/test/resources/images/" + picture), "Apache Logo");
733         final String htmlMsg = "<html><img src=\"cid:" + cid + "\"><html>";
734         htmlEmail.setHtmlMsg(htmlMsg);
735         htmlEmail.buildMimeMessage();
736 
737         final MimeMessage mm = htmlEmail.getMimeMessage();
738         mm.saveChanges();
739         final MimeMessageParser mmp = new MimeMessageParser(mm);
740         mmp.parse();
741 
742         final List<?> attachments = mmp.getAttachmentList();
743         assertEquals("Attachment size", 1, attachments.size());
744 
745         final DataSource ds = (DataSource) attachments.get(0);
746         assertEquals("Content type", contentType, ds.getContentType());
747     }
748 
749     private HtmlEmail createDefaultHtmlEmail() throws EmailException {
750         final HtmlEmail htmlEmail = new HtmlEmail();
751         htmlEmail.setHostName(this.strTestMailServer);
752         htmlEmail.setSmtpPort(this.getMailServerPort());
753         htmlEmail.setFrom("a@b.com");
754         htmlEmail.addTo("c@d.com");
755         return htmlEmail;
756     }
757 }