You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mail-templates.zh-cn.md 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. ---
  2. date: "2023-05-23T09:00:00+08:00"
  3. title: "邮件模板"
  4. slug: "mail-templates"
  5. sidebar_position: 45
  6. toc: false
  7. draft: false
  8. aliases:
  9. - /zh-cn/mail-templates
  10. menu:
  11. sidebar:
  12. parent: "administration"
  13. name: "邮件模板"
  14. sidebar_position: 45
  15. identifier: "mail-templates"
  16. ---
  17. # 邮件模板
  18. 为了定制特定操作的电子邮件主题和内容,可以使用模板来自定义 Gitea。这些功能的模板位于 [`custom` 目录](administration/customizing-gitea.md) 下。
  19. 如果没有自定义的替代方案,Gitea 将使用内部模板作为默认模板。
  20. 自定义模板在 Gitea 启动时加载。对它们的更改在 Gitea 重新启动之前不会被识别。
  21. ## 支持模板的邮件通知
  22. 目前,以下通知事件使用模板:
  23. | 操作名称 | 用途 |
  24. | ----------- | ------------------------------------------------------------------------------------------------------------ |
  25. | `new` | 创建了新的工单或合并请求。 |
  26. | `comment` | 在现有工单或合并请求中创建了新的评论。 |
  27. | `close` | 关闭了工单或合并请求。 |
  28. | `reopen` | 重新打开了工单或合并请求。 |
  29. | `review` | 在合并请求中进行审查的首要评论。 |
  30. | `approve` | 对合并请求进行批准的首要评论。 |
  31. | `reject` | 对合并请求提出更改请求的审查的首要评论。 |
  32. | `code` | 关于合并请求的代码的单个评论。 |
  33. | `assigned` | 用户被分配到工单或合并请求。 |
  34. | `default` | 未包括在上述类别中的任何操作,或者当对应类别的模板不存在时使用的模板。 |
  35. 特定消息类型的模板路径为:
  36. ```sh
  37. custom/templates/mail/{操作类型}/{操作名称}.tmpl
  38. ```
  39. 其中 `{操作类型}` 是 `issue` 或 `pull`(针对合并请求),`{操作名称}` 是上述列出的操作名称之一。
  40. 例如,有关合并请求中的评论的电子邮件的特定模板是:
  41. ```sh
  42. custom/templates/mail/pull/comment.tmpl
  43. ```
  44. 然而,并不需要为每个操作类型/名称组合创建模板。
  45. 使用回退系统来选择适当的模板。在此列表中,将使用 _第一个存在的_ 模板:
  46. - 所需**操作类型**和**操作名称**的特定模板。
  47. - 操作类型为 `issue` 和所需**操作名称**的模板。
  48. - 所需**操作类型**和操作名称为 `default` 的模板。
  49. - 操作类型为` issue` 和操作名称为 `default` 的模板。
  50. 唯一必需的模板是操作类型为 `issue` 操作名称为 `default` 的模板,除非用户在 `custom` 目录中覆盖了它。
  51. ## 模板语法
  52. 邮件模板是 UTF-8 编码的文本文件,需要遵循以下格式之一:
  53. ```
  54. 用于主题行的文本和宏
  55. ------------
  56. 用于邮件正文的文本和宏
  57. ```
  58. 或者
  59. ```
  60. 用于邮件正文的文本和宏
  61. ```
  62. 指定 _主题_ 部分是可选的(因此也是虚线分隔符)。在使用时,_主题_ 和 _邮件正文_ 模板之间的分隔符需要至少三个虚线;分隔符行中不允许使用其他字符。
  63. _主题_ 和 _邮件正文_ 由 [Golang的模板引擎](https://go.dev/pkg/text/template/) 解析,并提供了为每个通知组装的 _元数据上下文_。上下文包含以下元素:
  64. | 名称 | 类型 | 可用性 | 用途 |
  65. | -------------------- | ------------------ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  66. | `.FallbackSubject` | string | 始终可用 | 默认主题行。参见下文。 |
  67. | `.Subject` | string | 仅在正文中可用 | 解析后的 _主题_。 |
  68. | `.Body` | string | 始终可用 | 工单、合并请求或评论的消息,从 Markdown 解析为 HTML 并进行了清理。请勿与 _邮件正文_ 混淆。 |
  69. | `.Link` | string | 始终可用 | 源工单、合并请求或评论的地址。 |
  70. | `.Issue` | models.Issue | 始终可用 | 产生通知的工单(或合并请求)。要获取特定于合并请求的数据(例如 `HasMerged`),可以使用 `.Issue.PullRequest`,但需要注意,如果工单 _不是_ 合并请求,则该字段将为 `nil`。 |
  71. | `.Comment` | models.Comment | 如果适用 | 如果通知是针对添加到工单或合并请求的评论,则其中包含有关评论的信息。 |
  72. | `.IsPull` | bool | 始终可用 | 如果邮件通知与合并请求关联(即 `.Issue.PullRequest` 不为 `nil` ),则为 `true`。 |
  73. | `.Repo` | string | 始终可用 | 仓库的名称,包括所有者名称(例如 `mike/stuff`) |
  74. | `.User` | models.User | 始终可用 | 事件来源仓库的所有者。要获取用户名(例如 `mike`),可以使用 `.User.Name`。 |
  75. | `.Doer` | models.User | 始终可用 | 执行触发通知事件的操作的用户。要获取用户名(例如 `rhonda`),可以使用 `.Doer.Name`。 |
  76. | `.IsMention` | bool | 始终可用 | 如果此通知仅是因为在评论中提到了用户而生成的,并且收件人未订阅源,则为 `true`。如果收件人已订阅工单或仓库,则为 `false`。 |
  77. | `.SubjectPrefix` | string | 始终可用 | 如果通知是关于除工单或合并请求创建之外的其他内容,则为 `Re:`;否则为空字符串。 |
  78. | `.ActionType` | string | 始终可用 | `"issue"` 或 `"pull"`。它将与实际的 _操作类型_ 对应,与选择的模板无关。 |
  79. | `.ActionName` | string | 始终可用 | 它将是上述操作类型之一(`new` ,`comment` 等),并与选择的模板对应。 |
  80. | `.ReviewComments` | []models.Comment | 始终可用 | 审查中的代码评论列表。评论文本将在 `.RenderedContent` 中,引用的代码将在 `.Patch` 中。 |
  81. 所有名称区分大小写。
  82. ### 模板中的主题部分
  83. 用于邮件主题的模板引擎是 Golang 的 [`text/template`](https://go.dev/pkg/text/template/)。
  84. 有关语法的详细信息,请参阅链接的文档。
  85. 主题构建的步骤如下:
  86. - 根据通知类型和可用的模板选择一个模板。
  87. - 解析并解析模板(例如,将 `{{.Issue.Index}}` 转换为工单或合并请求的编号)。
  88. - 将所有空格字符(例如 `TAB`,`LF` 等)转换为普通空格。
  89. - 删除所有前导、尾随和多余的空格。
  90. - 将字符串截断为前 256 个字母(字符)。
  91. 如果最终结果为空字符串,**或者**没有可用的主题模板(即所选模板不包含主题部分),将使用Gitea的**内部默认值**。
  92. 内部默认(回退)主题相当于:
  93. ```
  94. {{.SubjectPrefix}}[{{.Repo}}] {{.Issue.Title}} (#{{.Issue.Index}})
  95. ```
  96. 例如:`Re: [mike/stuff] New color palette (#38)`
  97. 即使存在有效的主题模板,Gitea的默认主题也可以在模板的元数据中作为 `.FallbackSubject` 找到。
  98. ### 模板中的邮件正文部分
  99. 用于邮件正文的模板引擎是 Golang 的 [`html/template`](https://go.dev/pkg/html/template/)。
  100. 有关语法的详细信息,请参阅链接的文档。
  101. 邮件正文在邮件主题之后进行解析,因此还有一个额外的 _元数据_ 字段,即在考虑所有情况之后实际呈现的主题。
  102. 期望的结果是 HTML(包括结构元素,如`<html>`,`<body>`等)。可以通过 `<style>` 块、`class` 和 `style` 属性进行样式设置。但是,`html/template` 会进行一些 [自动转义](https://go.dev/pkg/html/template/#hdr-Contexts),需要考虑这一点。
  103. 不支持附件(例如图像或外部样式表)。但是,也可以引用其他模板,例如以集中方式提供 `<style>` 元素的内容。外部模板必须放置在 `custom/mail` 下,并相对于该目录引用。例如,可以使用 `{{template styles/base}}` 包含 `custom/mail/styles/base.tmpl`。
  104. 邮件以 `Content-Type: multipart/alternative` 发送,因此正文以 HTML 和文本格式发送。通过剥离 HTML 标记来获取文本版本。
  105. ## 故障排除
  106. 邮件的呈现方式直接取决于邮件应用程序的功能。许多邮件客户端甚至不支持 HTML,因此显示生成邮件中包含的文本版本。
  107. 如果模板无法呈现,则只有在发送邮件时才会注意到。
  108. 如果主题模板失败,将使用默认主题,如果从 _邮件正文_ 中成功呈现了任何内容,则将使用该内容,忽略其他内容。
  109. 如果遇到问题,请检查 [Gitea的日志](administration/logging-config.md) 以获取错误消息。
  110. ## 示例
  111. `custom/templates/mail/issue/default.tmpl`:
  112. ```html
  113. [{{.Repo}}] @{{.Doer.Name}}
  114. {{if eq .ActionName "new"}}
  115. 创建了
  116. {{else if eq .ActionName "comment"}}
  117. 评论了
  118. {{else if eq .ActionName "close"}}
  119. 关闭了
  120. {{else if eq .ActionName "reopen"}}
  121. 重新打开了
  122. {{else}}
  123. 更新了
  124. {{end}}
  125. {{if eq .ActionType "issue"}}
  126. 工单
  127. {{else}}
  128. 合并请求
  129. {{end}}
  130. #{{.Issue.Index}}: {{.Issue.Title}}
  131. ------------
  132. <!DOCTYPE html>
  133. <html>
  134. <head>
  135. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  136. <title>{{.Subject}}</title>
  137. </head>
  138. <body>
  139. {{if .IsMention}}
  140. <p>
  141. 您收到此邮件是因为 @{{.Doer.Name}} 提到了您。
  142. </p>
  143. {{end}}
  144. <p>
  145. <p>
  146. <a href="{{AppUrl}}/{{.Doer.LowerName}}">@{{.Doer.Name}}</a>
  147. {{if not (eq .Doer.FullName "")}}
  148. ({{.Doer.FullName}})
  149. {{end}}
  150. {{if eq .ActionName "new"}}
  151. 创建了
  152. {{else if eq .ActionName "close"}}
  153. 关闭了
  154. {{else if eq .ActionName "reopen"}}
  155. 重新打开了
  156. {{else}}
  157. 更新了
  158. {{end}}
  159. <a href="{{.Link}}">{{.Repo}}#{{.Issue.Index}}</a>。
  160. </p>
  161. {{if not (eq .Body "")}}
  162. <h3>消息内容:</h3>
  163. <hr>
  164. {{.Body}}
  165. {{end}}
  166. </p>
  167. <hr>
  168. <p>
  169. <a href="{{.Link}}">在 Gitea 上查看</a>。
  170. </p>
  171. </body>
  172. </html>
  173. ```
  174. 该模板将生成以下内容:
  175. ### 主题
  176. > [mike/stuff] @rhonda 在合并请求 #38 上进行了评论:New color palette
  177. ### 邮件正文
  178. > [@rhonda](#)(Rhonda Myers)更新了 [mike/stuff#38](#)。
  179. >
  180. > #### 消息内容
  181. >
  182. > \_********************************\_********************************
  183. >
  184. > Mike, I think we should tone down the blues a little.
  185. >
  186. > \_********************************\_********************************
  187. >
  188. > [在 Gitea 上查看](#)。
  189. ## 高级用法
  190. 模板系统包含一些函数,可用于进一步处理和格式化消息。以下是其中一些函数的列表:
  191. | 函数名 | 参数 | 可用于 | 用法 |
  192. |------------------| ----------- | ------------ | ------------------------------ |
  193. | `AppUrl` | - | 任何地方 | Gitea 的 URL |
  194. | `AppName` | - | 任何地方 | 从 `app.ini` 中设置,通常为 "Gitea" |
  195. | `AppDomain` | - | 任何地方 | Gitea 的主机名 |
  196. | `EllipsisString` | string, int | 任何地方 | 将字符串截断为指定长度;根据需要添加省略号 |
  197. | `SanitizeHTML` | string | 仅正文部分 | 通过删除其中的危险 HTML 标签对文本进行清理 |
  198. | `SafeHTML` | string | 仅正文部分 | 将输入作为 HTML 处理;可用于输出原始的 HTML 内容 |
  199. 这些都是 _函数_,而不是元数据,因此必须按以下方式使用:
  200. ```html
  201. 像这样使用: {{SanitizeHTML "Escape<my>text"}}
  202. 或者这样使用: {{"Escape<my>text" | SanitizeHTML}}
  203. 或者这样使用: {{AppUrl}}
  204. 但不要像这样使用: {{.AppUrl}}
  205. ```