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