在使用Thymeleaf生成的HTML文档中添加<img>标签。

5
在我的Spring Boot应用程序中,我正在使用Thymeleaf生成HTML电子邮件。我想在这些电子邮件中包含一个。图像存储在/src/main/resources/static/img/logo.png。
我确认可以通过在浏览器中请求http://localhost:8080/img/logo.svg来启动本地应用程序并解析图像。
为了在HTML中包含此图像,我已经尝试了以下所有内容:
1. 2. 3. 4. Base64编码的图像 每个的结果是:
1. 抛出异常:org.thymeleaf.exceptions.TemplateProcessingException:除非用于执行引擎的上下文实现了org.thymeleaf.context.IWebContext接口,否则链接基础“/img/logo.svg”无法是上下文相关的(/ ...) 2. 渲染出,在电子邮件中显示为损坏的图像。 3. 渲染出,在电子邮件中显示为损坏的图像。 4. 大多数测试的邮件客户端都会渲染出该图像,但它被Gmail阻止,并且没有办法通过设置来取消阻止。
我猜为了在电子邮件中正确呈现图像,我需要提供绝对URL,但是我不确定如何做到这一点。
问题的一部分是很难确定电子邮件未显示是否因为URL不正确或邮件客户端阻止图像。
更新
我认为这显而易见,但显然不是:我不能使用任何硬编码主机名为localhost:8080的解决方案,因为这只是我在本地运行时使用的URL,而且我也需要它在其他环境中工作,例如生产。

问题是“你查看HTML的表单”.... ;) - xerx593
1
@xerx593如果你有答案,能否请你把它发布为一个回答呢? - Dónal
邮件中的 URL 必须能够在目标客户端上访问(也就是说,在打开电子邮件的设备上)。此外,许多邮件 Web 客户端会通过自己的服务器代理外部 URL。它们可能会禁止像“localhost”这样的主机。还要注意,许多邮件客户端不支持 SVG 图像:https://dev59.com/d1oU5IYBdhLWcg3wK0pX - Felix
@Dónal 我刚刚编辑了我的评论。许多电子邮件客户端不支持SVG图像。HTML邮件支持的内容比常规网页少得多。 - Felix
@Felix 我的问题就是如何做到这一点。 - Dónal
显示剩余8条评论
2个回答

2

高级

您可以声明一个属性来引入“公共URL”(例如在application.properties中):

public_domain=http://somwhere.com

使用方法如下:
<img th:src="@{|${public_domain}/img/logo.svg|}" />

点击这里


完全动态
<img th:scr="${#httpServletRequest.scheme}+'://'+${#httpServletRequest.serverName}+':'+${#httpServletRequest.serverPort}+@{img/logo.svg}" />
超酷!(这只有在存在http(servlet)请求的情况下才有效,似乎在此并不相关。)

深入了解

你永远不知道使用任何客户端(信任任何服务器...并从中加载图像)的人是谁在“监视”你的电子邮件!!?...

因此,在[so]这里,在HTML电子邮件中嵌入图像是一个“非常流行”的问题。

应用于thymeleaf:他们有一篇额外的文章介绍如何实现!!(还显示img附件.. 在html和文本中都可以工作(没有图像;()!!!;)

总结一下,一旦配置了邮件和模板:

模板:

 <img src="sample.png" th:src="|cid:${imageResourceName}|" />

“img”元素有一个硬编码的“src”值,适用于原型设计。在运行时,“src”值将被类似于“cid:image.jpg”的内容替换,匹配附加的图像文件名称。
String imageResourceName = ...
byte[] imageBytes = ...
String imageContentType = ...

// Prepare the evaluation context
final Context ctx = new Context(locale);
...
ctx.setVariable("imageResourceName", imageResourceName); // so that we can reference it from HTML

// Prepare message using a Spring helper
final MimeMessage mimeMessage = this.mailSender.createMimeMessage();
final MimeMessageHelper message = ...
message.set...

// Create the HTML body using Thymeleaf
final String htmlContent = ...

// Add the inline image, referenced from the HTML code as "cid:${imageResourceName}" !!!
final InputStreamSource imageSource = new ByteArrayResource(imageBytes);
message.addInline(imageResourceName, imageSource, imageContentType);

// Send mail ...

请注意,OP在HTTPRequest的上下文中没有使用Thymeleaf。他将Thymeleaf作为模板引擎用于生成HTML电子邮件。 - Felix
是的,“完全动态”的功能只在那种(http请求)情况下才能使用!仍然有些困惑:OP使用http://localhost:8080(可能是使用spring-boot来提供图像),但仍然“缺少IWebContext”。 - xerx593
我喜欢你的编辑。对于未来的读者,请注意,示例将实际图像数据嵌入电子邮件中,因此一旦用户打开电子邮件,就不会向您的Web服务器发出请求。因此,这种方式无法提供动态图像。 - Felix
设计上也不可能发送“动态邮件”! ;) - xerx593
发送后电子邮件不能更改吗? - xerx593
显示剩余2条评论

0

因此,从“战略”上讲,我们有两个选择:

  • A:通过公共服务器提供图像(使用静态URL)。
  • B:将图像“与电子邮件正文一起”发送。

(优缺点...)

A

我们应该按照 Thymeleaf 提出的建议,将其作为“绝对 URL”来处理:

绝对 URL 允许您创建到其他服务器的链接。它们以指定协议名称(http:// 或 https://)开头...

它们不会被修改(除非您在服务器上配置了 URL 重写过滤器并在 HttpServletResponse.encodeUrl(...) 方法中执行修改)...

<img th:src="@{http://localhost:8080/img/logo.svg}" />

这将被渲染为:

<img src="http://localhost:8080/img/logo.svg" />

(无论邮件客户端如何处理它)

我们可以通过引入并使用一些占位符(例如不同环境)来推进这种方法:

(例如)application.properties:

public_domain=http://somewhere.com

使用方法如下:

<img th:src="@{|${public_domain}/img/logo.svg|}" />

在这里点赞。

B

在这里,我们(技术上)有以下选项:

  • 内联附加(<img th:src="@{data...}")(例如,如此处所示{{link1:}})
  • 或者使用CID(多部分)附加,如{{link2:Thymeleaf文章}}所示。
  • ...

{{link2:Thymeleaf文章}}的大纲,一旦配置了模板和邮件,如下:

模板HTML:

 <img src="/path/when/not/thymeleaf-generated/logo.svg" th:src="|cid:${imageResourceName}|" />
元素有一个硬编码的src值 - 用于原型设计 - 运行时将被类似于cid:image.jpg匹配附加图像文件名的内容所替换。

Java服务:

String imageResourceName = ...
byte[] imageBytes = ...
String imageContentType = ... // availabe!

// Prepare the evaluation context
final Context ctx = new Context(locale);
...
ctx.setVariable("imageResourceName", imageResourceName); // so that we can reference it from HTML

// See Article...

// Add the inline image, referenced from the HTML code as "cid:${imageResourceName}" !!!
final InputStreamSource imageSource = new ByteArrayResource(imageBytes);
message.addInline(imageResourceName, imageSource, imageContentType);

// Send mail ...

抱歉,答案相同,但结构和不同方面略有不同。关于“优缺点”,请参见评论、链接或其他答案。 :) - xerx593

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接