邮件模板

为了定制特定操作的电子邮件主题和内容,可以使用模板来自定义 Gitea。这些功能的模板位于 custom 目录 下。 如果没有自定义的替代方案,Gitea 将使用内部模板作为默认模板。

自定义模板在 Gitea 启动时加载。对它们的更改在 Gitea 重新启动之前不会被识别。

支持模板的邮件通知

目前,以下通知事件使用模板:

操作名称用途
new创建了新的工单或合并请求。
comment在现有工单或合并请求中创建了新的评论。
close关闭了工单或合并请求。
reopen重新打开了工单或合并请求。
review在合并请求中进行审查的首要评论。
approve对合并请求进行批准的首要评论。
reject对合并请求提出更改请求的审查的首要评论。
code关于合并请求的代码的单个评论。
assigned用户被分配到工单或合并请求。
default未包括在上述类别中的任何操作,或者当对应类别的模板不存在时使用的模板。

特定消息类型的模板路径为:

  1. custom/templates/mail/{操作类型}/{操作名称}.tmpl

其中 {操作类型}issuepull(针对合并请求),{操作名称} 是上述列出的操作名称之一。

例如,有关合并请求中的评论的电子邮件的特定模板是:

  1. custom/templates/mail/pull/comment.tmpl

然而,并不需要为每个操作类型/名称组合创建模板。 使用回退系统来选择适当的模板。在此列表中,将使用 第一个存在的 模板:

  • 所需操作类型操作名称的特定模板。
  • 操作类型为 issue 和所需操作名称的模板。
  • 所需操作类型和操作名称为 default 的模板。
  • 操作类型为 issue 和操作名称为 default 的模板。

唯一必需的模板是操作类型为 issue 操作名称为 default 的模板,除非用户在 custom 目录中覆盖了它。

模板语法

邮件模板是 UTF-8 编码的文本文件,需要遵循以下格式之一:

  1. 用于主题行的文本和宏
  2. ------------
  3. 用于邮件正文的文本和宏

或者

  1. 用于邮件正文的文本和宏

指定 主题 部分是可选的(因此也是虚线分隔符)。在使用时,主题邮件正文 模板之间的分隔符需要至少三个虚线;分隔符行中不允许使用其他字符。

主题邮件正文Golang的模板引擎 解析,并提供了为每个通知组装的 元数据上下文。上下文包含以下元素:

名称类型可用性用途
.FallbackSubjectstring始终可用默认主题行。参见下文。
.Subjectstring仅在正文中可用解析后的 主题
.Bodystring始终可用工单、合并请求或评论的消息,从 Markdown 解析为 HTML 并进行了清理。请勿与 邮件正文 混淆。
.Linkstring始终可用源工单、合并请求或评论的地址。
.Issuemodels.Issue始终可用产生通知的工单(或合并请求)。要获取特定于合并请求的数据(例如 HasMerged),可以使用 .Issue.PullRequest,但需要注意,如果工单 不是 合并请求,则该字段将为 nil
.Commentmodels.Comment如果适用如果通知是针对添加到工单或合并请求的评论,则其中包含有关评论的信息。
.IsPullbool始终可用如果邮件通知与合并请求关联(即 .Issue.PullRequest 不为 nil ),则为 true
.Repostring始终可用仓库的名称,包括所有者名称(例如 mike/stuff
.Usermodels.User始终可用事件来源仓库的所有者。要获取用户名(例如 mike),可以使用 .User.Name
.Doermodels.User始终可用执行触发通知事件的操作的用户。要获取用户名(例如 rhonda),可以使用 .Doer.Name
.IsMentionbool始终可用如果此通知仅是因为在评论中提到了用户而生成的,并且收件人未订阅源,则为 true。如果收件人已订阅工单或仓库,则为 false
.SubjectPrefixstring始终可用如果通知是关于除工单或合并请求创建之外的其他内容,则为 Re:;否则为空字符串。
.ActionTypestring始终可用“issue”“pull”。它将与实际的 操作类型 对应,与选择的模板无关。
.ActionNamestring始终可用它将是上述操作类型之一(newcomment 等),并与选择的模板对应。
.ReviewComments[]models.Comment始终可用审查中的代码评论列表。评论文本将在 .RenderedContent 中,引用的代码将在 .Patch 中。

所有名称区分大小写。

模板中的主题部分

用于邮件主题的模板引擎是 Golang 的 text/template。 有关语法的详细信息,请参阅链接的文档。

主题构建的步骤如下:

  • 根据通知类型和可用的模板选择一个模板。
  • 解析并解析模板(例如,将 {{.Issue.Index}} 转换为工单或合并请求的编号)。
  • 将所有空格字符(例如 TABLF 等)转换为普通空格。
  • 删除所有前导、尾随和多余的空格。
  • 将字符串截断为前 256 个字母(字符)。

如果最终结果为空字符串,或者没有可用的主题模板(即所选模板不包含主题部分),将使用Gitea的内部默认值

内部默认(回退)主题相当于:

  1. {{.SubjectPrefix}}[{{.Repo}}] {{.Issue.Title}} (#{{.Issue.Index}})

例如:Re: [mike/stuff] New color palette (#38)

即使存在有效的主题模板,Gitea的默认主题也可以在模板的元数据中作为 .FallbackSubject 找到。

模板中的邮件正文部分

用于邮件正文的模板引擎是 Golang 的 html/template。 有关语法的详细信息,请参阅链接的文档。

邮件正文在邮件主题之后进行解析,因此还有一个额外的 元数据 字段,即在考虑所有情况之后实际呈现的主题。

期望的结果是 HTML(包括结构元素,如<html><body>等)。可以通过 <style> 块、classstyle 属性进行样式设置。但是,html/template 会进行一些 自动转义,需要考虑这一点。

不支持附件(例如图像或外部样式表)。但是,也可以引用其他模板,例如以集中方式提供 <style> 元素的内容。外部模板必须放置在 custom/mail 下,并相对于该目录引用。例如,可以使用 {{template styles/base}} 包含 custom/mail/styles/base.tmpl

邮件以 Content-Type: multipart/alternative 发送,因此正文以 HTML 和文本格式发送。通过剥离 HTML 标记来获取文本版本。

故障排除

邮件的呈现方式直接取决于邮件应用程序的功能。许多邮件客户端甚至不支持 HTML,因此显示生成邮件中包含的文本版本。

如果模板无法呈现,则只有在发送邮件时才会注意到。 如果主题模板失败,将使用默认主题,如果从 邮件正文 中成功呈现了任何内容,则将使用该内容,忽略其他内容。

如果遇到问题,请检查 Gitea的日志 以获取错误消息。

示例

custom/templates/mail/issue/default.tmpl:

  1. [{{.Repo}}] @{{.Doer.Name}}
  2. {{if eq .ActionName "new"}}
  3. 创建了
  4. {{else if eq .ActionName "comment"}}
  5. 评论了
  6. {{else if eq .ActionName "close"}}
  7. 关闭了
  8. {{else if eq .ActionName "reopen"}}
  9. 重新打开了
  10. {{else}}
  11. 更新了
  12. {{end}}
  13. {{if eq .ActionType "issue"}}
  14. 工单
  15. {{else}}
  16. 合并请求
  17. {{end}}
  18. #{{.Issue.Index}}: {{.Issue.Title}}
  19. ------------
  20. <!DOCTYPE html>
  21. <html>
  22. <head>
  23. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  24. <title>{{.Subject}}</title>
  25. </head>
  26. <body>
  27. {{if .IsMention}}
  28. <p>
  29. 您收到此邮件是因为 @{{.Doer.Name}} 提到了您。
  30. </p>
  31. {{end}}
  32. <p>
  33. <p>
  34. <a href="{{AppUrl}}/{{.Doer.LowerName}}">@{{.Doer.Name}}</a>
  35. {{if not (eq .Doer.FullName "")}}
  36. ({{.Doer.FullName}})
  37. {{end}}
  38. {{if eq .ActionName "new"}}
  39. 创建了
  40. {{else if eq .ActionName "close"}}
  41. 关闭了
  42. {{else if eq .ActionName "reopen"}}
  43. 重新打开了
  44. {{else}}
  45. 更新了
  46. {{end}}
  47. <a href="{{.Link}}">{{.Repo}}#{{.Issue.Index}}</a>。
  48. </p>
  49. {{if not (eq .Body "")}}
  50. <h3>消息内容:</h3>
  51. <hr>
  52. {{.Body | Str2html}}
  53. {{end}}
  54. </p>
  55. <hr>
  56. <p>
  57. <a href="{{.Link}}">在 Gitea 上查看</a>。
  58. </p>
  59. </body>
  60. </html>

该模板将生成以下内容:

主题

[mike/stuff] @rhonda 在合并请求 #38 上进行了评论:New color palette

邮件正文

@rhonda(Rhonda Myers)更新了 mike/stuff#38

消息内容:

_**_**

Mike, I think we should tone down the blues a little.

_**_**

在 Gitea 上查看

高级用法

模板系统包含一些函数,可用于进一步处理和格式化消息。以下是其中一些函数的列表:

函数名参数可用于用法
AppUrl-任何地方Gitea 的 URL
AppName-任何地方app.ini 中设置,通常为 “Gitea”
AppDomain-任何地方Gitea 的主机名
EllipsisStringstring, int任何地方将字符串截断为指定长度;根据需要添加省略号
Str2htmlstring仅正文部分通过删除其中的 HTML 标签对文本进行清理
Safestring仅正文部分将输入作为 HTML 处理;可用于 .ReviewComments.RenderedContent 等字段

这些都是 函数,而不是元数据,因此必须按以下方式使用:

  1. 像这样使用: {{Str2html "Escape<my>text"}}
  2. 或者这样使用: {{"Escape<my>text" | Str2html}}
  3. 或者这样使用: {{AppUrl}}
  4. 但不要像这样使用: {{.AppUrl}}