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.mail2.jakarta;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertThrows;
21  import static org.junit.jupiter.api.Assertions.assertTrue;
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.net.URL;
27  import java.nio.charset.StandardCharsets;
28  import java.util.List;
29  import java.util.logging.Level;
30  import java.util.logging.Logger;
31  import java.util.regex.Matcher;
32  import java.util.regex.Pattern;
33  
34  import org.apache.commons.io.FileUtils;
35  import org.apache.commons.io.IOUtils;
36  import org.apache.commons.mail2.core.EmailException;
37  import org.apache.commons.mail2.jakarta.mocks.MockImageHtmlEmailConcrete;
38  import org.apache.commons.mail2.jakarta.resolver.DataSourceClassPathResolver;
39  import org.apache.commons.mail2.jakarta.resolver.DataSourceCompositeResolver;
40  import org.apache.commons.mail2.jakarta.resolver.DataSourceUrlResolver;
41  import org.apache.commons.mail2.jakarta.util.MimeMessageParser;
42  import org.apache.commons.mail2.jakarta.util.MimeMessageUtils;
43  import org.junit.jupiter.api.BeforeEach;
44  import org.junit.jupiter.api.Test;
45  
46  import jakarta.activation.DataSource;
47  import jakarta.mail.internet.MimeMessage;
48  
49  public class ImageHtmlEmailTest extends HtmlEmailTest {
50  
51      private static final class MockDataSourceClassPathResolver extends DataSourceClassPathResolver {
52  
53          public MockDataSourceClassPathResolver(final String classPathBase, final boolean lenient) {
54              super(classPathBase, lenient);
55          }
56  
57          @Override
58          public DataSource resolve(final String resourceLocation, final boolean isLenient) throws IOException {
59              final jakarta.mail.util.ByteArrayDataSource ds = (jakarta.mail.util.ByteArrayDataSource) super.resolve(resourceLocation, isLenient);
60              ds.setName(null);
61              return ds;
62          }
63  
64      }
65  
66      private static final boolean TEST_IS_LENIENT = true;
67      private static final URL TEST_IMAGE_URL = ImageHtmlEmailTest.class.getResource("/images/asf_logo_wide.gif");
68      private static final File TEST_IMAGE_DIR = new File(TEST_IMAGE_URL.getPath()).getParentFile();
69      private static final URL TEST_HTML_URL = ImageHtmlEmailTest.class.getResource("/attachments/download_email.cgi.html");
70  
71      private static final URL TEST2_HTML_URL = ImageHtmlEmailTest.class.getResource("/attachments/classpathtest.html");
72  
73      private MockImageHtmlEmailConcrete email;
74  
75      private String loadUrlContent(final URL url) throws IOException {
76          try (final InputStream stream = url.openStream()) {
77              final StringBuilder html = new StringBuilder();
78              try {
79                  final List<String> lines = IOUtils.readLines(stream, StandardCharsets.UTF_8);
80                  for (final String line : lines) {
81                      html.append(line).append("\n");
82                  }
83              } finally {
84                  stream.close();
85              }
86              return html.toString();
87          }
88      }
89  
90      @BeforeEach
91      public void setupImageHtmlEmailTest() {
92          // reusable objects to be used across multiple tests
93          email = new MockImageHtmlEmailConcrete();
94      }
95      // Start of Tests
96  
97      @Test
98      public void testEmail127() throws Exception {
99          Logger.getLogger(ImageHtmlEmail.class.getName()).setLevel(Level.FINEST);
100 
101         getMailServer();
102 
103         final String strSubject = "Test HTML Send default with URL";
104 
105         // Create the email message
106         email = new MockImageHtmlEmailConcrete();
107         email.setHostName(strTestMailServer);
108         email.setSmtpPort(getMailServerPort());
109         email.setFrom(strTestMailFrom);
110         email.addTo(strTestMailTo);
111         email.setSubject(strSubject);
112         email.setDataSourceResolver(new DataSourceUrlResolver(TEST_IMAGE_DIR.toURI().toURL(), TEST_IS_LENIENT));
113 
114         // set the html message
115         email.setHtmlMsg("<html><body><img title=\"$\" src=\"http://www.apache.org/images/feather.gif\"/></body></html>");
116 
117         // send the email
118         email.send();
119 
120         fakeMailServer.stop();
121         // validate txt message
122         validateSend(fakeMailServer, strSubject, email.getHtml(), email.getFromAddress(), email.getToAddresses(), email.getCcAddresses(),
123                 email.getBccAddresses(), true);
124     }
125 
126     @Test
127     public void testRegex() {
128         final Pattern pattern = Pattern.compile(ImageHtmlEmail.REGEX_IMG_SRC);
129 
130         // ensure that the regex that we use is catching the cases correctly
131         Matcher matcher = pattern.matcher("<html><body><img src=\"h\"/></body></html>");
132         assertTrue(matcher.find());
133         assertEquals("h", matcher.group(2));
134 
135         matcher = pattern.matcher("<html><body><img id=\"laskdasdkj\" src=\"h\"/></body></html>");
136         assertTrue(matcher.find());
137         assertEquals("h", matcher.group(2));
138 
139         // uppercase
140         matcher = pattern.matcher("<html><body><IMG id=\"laskdasdkj\" SRC=\"h\"/></body></html>");
141         assertTrue(matcher.find());
142         assertEquals("h", matcher.group(2));
143 
144         // matches twice
145         matcher = pattern.matcher(
146                 "<html><body><img id=\"laskdasdkj\" src=\"http://dstadler1.org/\"/><img id=\"laskdasdkj\" src=\"http://dstadler2.org/\"/></body></html>");
147         assertTrue(matcher.find());
148         assertEquals("http://dstadler1.org/", matcher.group(2));
149         assertTrue(matcher.find());
150         assertEquals("http://dstadler2.org/", matcher.group(2));
151 
152         // what about newlines
153         matcher = pattern.matcher(
154                 "<html><body><img\n \rid=\"laskdasdkj\"\n \rsrc=\"http://dstadler1.org/\"/><img id=\"laskdasdkj\" src=\"http://dstadler2.org/\"/></body></html>");
155         assertTrue(matcher.find());
156         assertEquals("http://dstadler1.org/", matcher.group(2));
157         assertTrue(matcher.find());
158         assertEquals("http://dstadler2.org/", matcher.group(2));
159 
160         // what about newlines and other whitespaces
161         matcher = pattern.matcher(
162                 "<html><body><img\n \t\rid=\"laskdasdkj\"\n \rsrc \n =\r  \"http://dstadler1.org/\"/><img  \r  id=\" laskdasdkj\"    src    =   \"http://dstadler2.org/\"/></body></html>");
163         assertTrue(matcher.find());
164         assertEquals("http://dstadler1.org/", matcher.group(2));
165         assertTrue(matcher.find());
166         assertEquals("http://dstadler2.org/", matcher.group(2));
167 
168         // what about some real markup
169         matcher = pattern.matcher(
170                 "<img alt=\"Chart?ck=xradar&amp;w=120&amp;h=120&amp;c=7fff00|7fff00&amp;m=4&amp;g=0\" src=\"/chart?ck=xradar&amp;w=120&amp;h=120&amp;c=7fff00|7fff00&amp;m=4&amp;g=0.2&amp;l=A,C,S,T&amp;v=3.0,3.0,2.0,2.0\"");
171         assertTrue(matcher.find());
172         assertEquals("/chart?ck=xradar&amp;w=120&amp;h=120&amp;c=7fff00|7fff00&amp;m=4&amp;g=0.2&amp;l=A,C,S,T&amp;v=3.0,3.0,2.0,2.0", matcher.group(2));
173 
174         // had a problem with multiple img-source tags
175         matcher = pattern.matcher("<img src=\"file1\"/><img src=\"file2\"/>");
176         assertTrue(matcher.find());
177         assertEquals("file1", matcher.group(2));
178         assertTrue(matcher.find());
179         assertEquals("file2", matcher.group(2));
180 
181         matcher = pattern.matcher("<img src=\"file1\"/><img src=\"file2\"/><img src=\"file3\"/><img src=\"file4\"/><img src=\"file5\"/>");
182         assertTrue(matcher.find());
183         assertEquals("file1", matcher.group(2));
184         assertTrue(matcher.find());
185         assertEquals("file2", matcher.group(2));
186         assertTrue(matcher.find());
187         assertEquals("file3", matcher.group(2));
188         assertTrue(matcher.find());
189         assertEquals("file4", matcher.group(2));
190         assertTrue(matcher.find());
191         assertEquals("file5", matcher.group(2));
192 
193         // try with invalid HTML that is seems sometimes, i.e. without closing "/" or "</img>"
194         matcher = pattern.matcher("<img src=\"file1\"><img src=\"file2\">");
195         assertTrue(matcher.find());
196         assertEquals("file1", matcher.group(2));
197         assertTrue(matcher.find());
198         assertEquals("file2", matcher.group(2));
199     }
200 
201     @Test
202     public void testSendClassPathFileWithNullName() throws Exception {
203         Logger.getLogger(ImageHtmlEmail.class.getName()).setLevel(Level.FINEST);
204 
205         // Create the email message
206         getMailServer();
207 
208         final String strSubject = "Test HTML Send default";
209 
210         email = new MockImageHtmlEmailConcrete();
211         email.setDataSourceResolver(new MockDataSourceClassPathResolver("/", TEST_IS_LENIENT));
212         email.setHostName(strTestMailServer);
213         email.setSmtpPort(getMailServerPort());
214         email.setFrom(strTestMailFrom);
215         email.addTo(strTestMailTo);
216         email.setSubject(strSubject);
217 
218         final String html = loadUrlContent(TEST2_HTML_URL);
219 
220         // set the html message
221         email.setHtmlMsg(html);
222 
223         // set the alternative message
224         email.setTextMsg("Your email client does not support HTML messages");
225 
226         // send the email
227         email.send();
228 
229         fakeMailServer.stop();
230 
231         assertEquals(1, fakeMailServer.getMessages().size());
232         final MimeMessage mimeMessage = fakeMailServer.getMessages().get(0).getMimeMessage();
233         MimeMessageUtils.writeMimeMessage(mimeMessage, new File("./target/test-emails/testSendClassPathFileWithNullName.eml"));
234 
235         final MimeMessageParser mimeMessageParser = new MimeMessageParser(mimeMessage).parse();
236         assertTrue(mimeMessageParser.getHtmlContent().contains("\"cid:"));
237         assertEquals(1, mimeMessageParser.getAttachmentList().size());
238     }
239 
240     @Test
241     public void testSendEmptyHTML() throws Exception {
242         Logger.getLogger(ImageHtmlEmail.class.getName()).setLevel(Level.FINEST);
243 
244         // Create the email message
245         final ImageHtmlEmail email = new ImageHtmlEmail();
246 
247         // set the HTML message
248         final EmailException e = assertThrows(EmailException.class, () -> email.setHtmlMsg(null));
249         assertTrue(e.getMessage().contains("Invalid message."), e.getMessage());
250     }
251 
252     @Test
253     public void testSendEmptyHTML2() throws Exception {
254         Logger.getLogger(ImageHtmlEmail.class.getName()).setLevel(Level.FINEST);
255 
256         // Create the email message
257         final ImageHtmlEmail email = new ImageHtmlEmail();
258 
259         // set the HTML message
260         final EmailException e = assertThrows(EmailException.class, () -> email.setHtmlMsg(""));
261         assertTrue(e.getMessage().contains("Invalid message."), e.getMessage());
262 
263     }
264 
265     @Test
266     public void testSendHtml() throws Exception {
267 
268         Logger.getLogger(ImageHtmlEmail.class.getName()).setLevel(Level.FINEST);
269 
270         // Create the email message
271         getMailServer();
272 
273         final String strSubject = "Test HTML Send default";
274 
275         email = new MockImageHtmlEmailConcrete();
276         email.setDataSourceResolver(new DataSourceUrlResolver(TEST_IMAGE_DIR.toURI().toURL(), TEST_IS_LENIENT));
277         email.setHostName(strTestMailServer);
278         email.setSmtpPort(getMailServerPort());
279         email.setFrom(strTestMailFrom);
280         email.addTo(strTestMailTo);
281         email.setSubject(strSubject);
282 
283         final String html = loadUrlContent(TEST_HTML_URL);
284 
285         // set the html message
286         email.setHtmlMsg(html);
287 
288         // set the alternative message
289         email.setTextMsg("Your email client does not support HTML messages");
290 
291         // send the email
292         email.send();
293 
294         fakeMailServer.stop();
295 
296         assertEquals(1, fakeMailServer.getMessages().size());
297         final MimeMessage mimeMessage = fakeMailServer.getMessages().get(0).getMimeMessage();
298 
299         final MimeMessageParser mimeMessageParser = new MimeMessageParser(mimeMessage).parse();
300         assertTrue(mimeMessageParser.getHtmlContent().contains("\"cid:"));
301         assertEquals(3, mimeMessageParser.getAttachmentList().size());
302     }
303 
304     @Test
305     public void testSendHTMLAbsoluteLocalFile() throws Exception {
306         Logger.getLogger(ImageHtmlEmail.class.getName()).setLevel(Level.FINEST);
307 
308         // Create the email message
309         getMailServer();
310 
311         final String strSubject = "Test HTML Send default with absolute local path";
312 
313         // Create the email message
314         email = new MockImageHtmlEmailConcrete();
315         email.setHostName(strTestMailServer);
316         email.setSmtpPort(getMailServerPort());
317         email.setFrom(strTestMailFrom);
318         email.addTo(strTestMailTo);
319         email.setSubject(strSubject);
320         email.setDataSourceResolver(new DataSourceUrlResolver(TEST_IMAGE_DIR.toURI().toURL(), TEST_IS_LENIENT));
321 
322         final File file = File.createTempFile("emailtest", ".tst");
323         FileUtils.writeStringToFile(file, "just some silly data that we won't be able to display anyway", StandardCharsets.UTF_8);
324 
325         // set the html message
326         email.setHtmlMsg("<html><body><img src=\"" + file.getAbsolutePath() + "\"/></body></html>");
327 
328         // send the email
329         email.send();
330 
331         fakeMailServer.stop();
332         // validate txt message
333         validateSend(fakeMailServer, strSubject, email.getHtml(), email.getFromAddress(), email.getToAddresses(), email.getCcAddresses(),
334                 email.getBccAddresses(), true);
335     }
336 
337     @Test
338     public void testSendHTMLAutoResolveFile() throws Exception {
339         Logger.getLogger(ImageHtmlEmail.class.getName()).setLevel(Level.FINEST);
340 
341         // Create the email message
342         getMailServer();
343 
344         final String strSubject = "Test HTML Send default";
345 
346         email = new MockImageHtmlEmailConcrete();
347         final DataSourceResolver[] dataSourceResolvers = new DataSourceResolver[2];
348         dataSourceResolvers[0] = new DataSourceUrlResolver(new URL("http://foo"), true);
349         dataSourceResolvers[1] = new DataSourceClassPathResolver("/", true);
350 
351         email.setDataSourceResolver(new DataSourceCompositeResolver(dataSourceResolvers));
352         email.setHostName(strTestMailServer);
353         email.setSmtpPort(getMailServerPort());
354         email.setFrom(strTestMailFrom);
355         email.addTo(strTestMailTo);
356         email.setSubject(strSubject);
357 
358         final String html = loadUrlContent(TEST2_HTML_URL);
359 
360         // set the html message
361         email.setHtmlMsg(html);
362 
363         // set the alternative message
364         email.setTextMsg("Your email client does not support HTML messages");
365 
366         // send the email
367         email.send();
368 
369         fakeMailServer.stop();
370 
371         assertEquals(1, fakeMailServer.getMessages().size());
372         final MimeMessage mimeMessage = fakeMailServer.getMessages().get(0).getMimeMessage();
373         MimeMessageUtils.writeMimeMessage(mimeMessage, new File("./target/test-emails/testSendHTMLAutoFile.eml"));
374 
375         final MimeMessageParser mimeMessageParser = new MimeMessageParser(mimeMessage).parse();
376         assertTrue(mimeMessageParser.getHtmlContent().contains("\"cid:"));
377         assertEquals(1, mimeMessageParser.getAttachmentList().size());
378     }
379 
380     @Test
381     public void testSendHTMLAutoResolveMultipleFiles() throws Exception {
382         Logger.getLogger(ImageHtmlEmail.class.getName()).setLevel(Level.FINEST);
383 
384         // Create the email message
385         getMailServer();
386 
387         final String strSubject = "Test HTML Send default";
388 
389         email = new MockImageHtmlEmailConcrete();
390         final DataSourceResolver dataSourceResolver = new DataSourceClassPathResolver("/", true);
391 
392         email.setDataSourceResolver(dataSourceResolver);
393         email.setHostName(strTestMailServer);
394         email.setSmtpPort(getMailServerPort());
395         email.setFrom(strTestMailFrom);
396         email.addTo(strTestMailTo);
397         email.setSubject(strSubject);
398 
399         final String html = "<p>First image  <img src=\"images/contentTypeTest.gif\"/></p>" + "<p>Second image <img src=\"images/contentTypeTest.jpg\"/></p>"
400                 + "<p>Third image  <img src=\"images/contentTypeTest.png\"/></p>";
401 
402         // set the html message
403         email.setHtmlMsg(html);
404 
405         // set the alternative message
406         email.setTextMsg("Your email client does not support HTML messages");
407 
408         // send the email
409         email.send();
410 
411         fakeMailServer.stop();
412 
413         assertEquals(1, fakeMailServer.getMessages().size());
414         final MimeMessage mimeMessage = fakeMailServer.getMessages().get(0).getMimeMessage();
415         MimeMessageUtils.writeMimeMessage(mimeMessage, new File("./target/test-emails/testSendHTMLAutoMultipleFiles.eml"));
416 
417         final MimeMessageParser mimeMessageParser = new MimeMessageParser(mimeMessage).parse();
418         assertTrue(mimeMessageParser.getHtmlContent().contains("\"cid:"), mimeMessageParser.getHtmlContent());
419         assertEquals(3, mimeMessageParser.getAttachmentList().size());
420     }
421 
422     @Test
423     public void testSendHTMLClassPathFile() throws Exception {
424         Logger.getLogger(ImageHtmlEmail.class.getName()).setLevel(Level.FINEST);
425 
426         // Create the email message
427         getMailServer();
428 
429         final String strSubject = "Test HTML Send default";
430 
431         email = new MockImageHtmlEmailConcrete();
432         email.setDataSourceResolver(new DataSourceClassPathResolver("/", TEST_IS_LENIENT));
433         email.setHostName(strTestMailServer);
434         email.setSmtpPort(getMailServerPort());
435         email.setFrom(strTestMailFrom);
436         email.addTo(strTestMailTo);
437         email.setSubject(strSubject);
438 
439         final String html = loadUrlContent(TEST2_HTML_URL);
440 
441         // set the html message
442         email.setHtmlMsg(html);
443 
444         // set the alternative message
445         email.setTextMsg("Your email client does not support HTML messages");
446 
447         // send the email
448         email.send();
449 
450         fakeMailServer.stop();
451 
452         assertEquals(1, fakeMailServer.getMessages().size());
453         final MimeMessage mimeMessage = fakeMailServer.getMessages().get(0).getMimeMessage();
454         MimeMessageUtils.writeMimeMessage(mimeMessage, new File("./target/test-emails/testSendHTMLClassPathFile.eml"));
455 
456         final MimeMessageParser mimeMessageParser = new MimeMessageParser(mimeMessage).parse();
457         assertTrue(mimeMessageParser.getHtmlContent().contains("\"cid:"));
458         assertEquals(1, mimeMessageParser.getAttachmentList().size());
459     }
460 
461     @Test
462     public void testSendHtmlUrl() throws Exception {
463         Logger.getLogger(ImageHtmlEmail.class.getName()).setLevel(Level.FINEST);
464 
465         getMailServer();
466 
467         final String strSubject = "Test HTML Send default with URL";
468 
469         // Create the email message
470         email = new MockImageHtmlEmailConcrete();
471         email.setHostName(strTestMailServer);
472         email.setSmtpPort(getMailServerPort());
473         email.setFrom(strTestMailFrom);
474         email.addTo(strTestMailTo);
475         email.setSubject(strSubject);
476         email.setDataSourceResolver(new DataSourceUrlResolver(TEST_IMAGE_DIR.toURI().toURL(), TEST_IS_LENIENT));
477 
478         // set the html message
479         email.setHtmlMsg("<html><body><img src=\"http://www.apache.org/images/feather.gif\"/></body></html>");
480 
481         // send the email
482         email.send();
483 
484         fakeMailServer.stop();
485         // validate txt message
486         validateSend(fakeMailServer, strSubject, email.getHtml(), email.getFromAddress(), email.getToAddresses(), email.getCcAddresses(),
487                 email.getBccAddresses(), true);
488     }
489 }