EMailTemplate.php 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright 2017, Morris Jobke <hey@morrisjobke.de>
  5. * @copyright 2017, Lukas Reschke <lukas@statuscode.ch>
  6. *
  7. * @author Bjoern Schiessle <bjoern@schiessle.org>
  8. * @author Joas Schilling <coding@schilljs.com>
  9. * @author Lukas Reschke <lukas@statuscode.ch>
  10. * @author Morris Jobke <hey@morrisjobke.de>
  11. *
  12. * @license GNU AGPL version 3 or any later version
  13. *
  14. * This program is free software: you can redistribute it and/or modify
  15. * it under the terms of the GNU Affero General Public License as
  16. * published by the Free Software Foundation, either version 3 of the
  17. * License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU Affero General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU Affero General Public License
  25. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  26. *
  27. */
  28. namespace OC\Mail;
  29. use OCP\Defaults;
  30. use OCP\IL10N;
  31. use OCP\IURLGenerator;
  32. use OCP\Mail\IEMailTemplate;
  33. /**
  34. * Class EMailTemplate
  35. *
  36. * addBodyText and addBodyButtonGroup automatically opens the body
  37. * addFooter, renderHtml, renderText automatically closes the body and the HTML if opened
  38. *
  39. * @package OC\Mail
  40. */
  41. class EMailTemplate implements IEMailTemplate {
  42. /** @var Defaults */
  43. protected $themingDefaults;
  44. /** @var IURLGenerator */
  45. protected $urlGenerator;
  46. /** @var IL10N */
  47. protected $l10n;
  48. /** @var string */
  49. protected $emailId;
  50. /** @var array */
  51. protected $data;
  52. /** @var string */
  53. protected $subject = '';
  54. /** @var string */
  55. protected $htmlBody = '';
  56. /** @var string */
  57. protected $plainBody = '';
  58. /** @var bool indicated if the footer is added */
  59. protected $headerAdded = false;
  60. /** @var bool indicated if the body is already opened */
  61. protected $bodyOpened = false;
  62. /** @var bool indicated if there is a list open in the body */
  63. protected $bodyListOpened = false;
  64. /** @var bool indicated if the footer is added */
  65. protected $footerAdded = false;
  66. protected $head = <<<EOF
  67. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  68. <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en" style="-webkit-font-smoothing:antialiased;background:#f3f3f3!important">
  69. <head>
  70. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  71. <meta name="viewport" content="width=device-width">
  72. <title></title>
  73. <style type="text/css">@media only screen{html{min-height:100%;background:#F5F5F5}}@media only screen and (max-width:610px){table.body img{width:auto;height:auto}table.body center{min-width:0!important}table.body .container{width:95%!important}table.body .columns{height:auto!important;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;padding-left:30px!important;padding-right:30px!important}th.small-12{display:inline-block!important;width:100%!important}table.menu{width:100%!important}table.menu td,table.menu th{width:auto!important;display:inline-block!important}table.menu.vertical td,table.menu.vertical th{display:block!important}table.menu[align=center]{width:auto!important}}</style>
  74. </head>
  75. <body style="-moz-box-sizing:border-box;-ms-text-size-adjust:100%;-webkit-box-sizing:border-box;-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;Margin:0;background:#f3f3f3!important;box-sizing:border-box;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;min-width:100%;padding:0;text-align:left;width:100%!important">
  76. <span class="preheader" style="color:#F5F5F5;display:none!important;font-size:1px;line-height:1px;max-height:0;max-width:0;mso-hide:all!important;opacity:0;overflow:hidden;visibility:hidden">
  77. </span>
  78. <table class="body" style="-webkit-font-smoothing:antialiased;Margin:0;background:#f3f3f3!important;border-collapse:collapse;border-spacing:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;height:100%;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;width:100%">
  79. <tr style="padding:0;text-align:left;vertical-align:top">
  80. <td class="center" align="center" valign="top" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
  81. <center data-parsed="" style="min-width:580px;width:100%">
  82. EOF;
  83. protected $tail = <<<EOF
  84. </center>
  85. </td>
  86. </tr>
  87. </table>
  88. <!-- prevent Gmail on iOS font size manipulation -->
  89. <div style="display:none;white-space:nowrap;font:15px courier;line-height:0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div>
  90. </body>
  91. </html>
  92. EOF;
  93. protected $header = <<<EOF
  94. <table align="center" class="wrapper header float-center" style="Margin:0 auto;background:#8a8a8a;background-color:%s;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%">
  95. <tr style="padding:0;text-align:left;vertical-align:top">
  96. <td class="wrapper-inner" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:20px;text-align:left;vertical-align:top;word-wrap:break-word">
  97. <table align="center" class="container" style="Margin:0 auto;background:0 0;border-collapse:collapse;border-spacing:0;margin:0 auto;padding:0;text-align:inherit;vertical-align:top;width:580px">
  98. <tbody>
  99. <tr style="padding:0;text-align:left;vertical-align:top">
  100. <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
  101. <table class="row collapse" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%%">
  102. <tbody>
  103. <tr style="padding:0;text-align:left;vertical-align:top">
  104. <center data-parsed="" style="min-width:580px;width:100%%">
  105. <img class="logo float-center" src="%s" alt="%s" align="center" style="-ms-interpolation-mode:bicubic;Margin:0 auto;clear:both;display:block;float:none;margin:0 auto;outline:0;text-align:center;text-decoration:none" height="50">
  106. </center>
  107. </tr>
  108. </tbody>
  109. </table>
  110. </td>
  111. </tr>
  112. </tbody>
  113. </table>
  114. </td>
  115. </tr>
  116. </table>
  117. <table class="spacer float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%">
  118. <tbody>
  119. <tr style="padding:0;text-align:left;vertical-align:top">
  120. <td height="80px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:80px;font-weight:400;hyphens:auto;line-height:80px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">&#xA0;</td>
  121. </tr>
  122. </tbody>
  123. </table>
  124. EOF;
  125. protected $heading = <<<EOF
  126. <table align="center" class="container main-heading float-center" style="Margin:0 auto;background:0 0!important;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:580px">
  127. <tbody>
  128. <tr style="padding:0;text-align:left;vertical-align:top">
  129. <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
  130. <h1 class="text-center" style="Margin:0;Margin-bottom:10px;color:inherit;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:24px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;text-align:center;word-wrap:normal">%s</h1>
  131. </td>
  132. </tr>
  133. </tbody>
  134. </table>
  135. <table class="spacer float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%">
  136. <tbody>
  137. <tr style="padding:0;text-align:left;vertical-align:top">
  138. <td height="40px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:40px;font-weight:400;hyphens:auto;line-height:40px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">&#xA0;</td>
  139. </tr>
  140. </tbody>
  141. </table>
  142. EOF;
  143. protected $bodyBegin = <<<EOF
  144. <table align="center" class="wrapper content float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%">
  145. <tr style="padding:0;text-align:left;vertical-align:top">
  146. <td class="wrapper-inner" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
  147. <table align="center" class="container has-shadow" style="Margin:0 auto;background:#fefefe;border-collapse:collapse;border-spacing:0;box-shadow:0 1px 2px 0 rgba(0,0,0,.2),0 1px 3px 0 rgba(0,0,0,.1);margin:0 auto;padding:0;text-align:inherit;vertical-align:top;width:580px">
  148. <tbody>
  149. <tr style="padding:0;text-align:left;vertical-align:top">
  150. <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
  151. <table class="spacer" style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%">
  152. <tbody>
  153. <tr style="padding:0;text-align:left;vertical-align:top">
  154. <td height="60px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:60px;font-weight:400;hyphens:auto;line-height:60px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">&#xA0;</td>
  155. </tr>
  156. </tbody>
  157. </table>
  158. EOF;
  159. protected $bodyText = <<<EOF
  160. <table class="row description" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%%">
  161. <tbody>
  162. <tr style="padding:0;text-align:left;vertical-align:top">
  163. <th class="small-12 large-12 columns first last" style="Margin:0 auto;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0 auto;padding:0;padding-bottom:30px;padding-left:30px;padding-right:30px;text-align:left;width:550px">
  164. <table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
  165. <tr style="padding:0;text-align:left;vertical-align:top">
  166. <th style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left">
  167. <p class="text-left" style="Margin:0;Margin-bottom:10px;color:#777;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;text-align:left">%s</p>
  168. </th>
  169. <th class="expander" style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0!important;text-align:left;visibility:hidden;width:0"></th>
  170. </tr>
  171. </table>
  172. </th>
  173. </tr>
  174. </tbody>
  175. </table>
  176. EOF;
  177. protected $listBegin = <<<EOF
  178. <table class="row description" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%%">
  179. <tbody>
  180. <tr style="padding:0;text-align:left;vertical-align:top">
  181. <th class="small-12 large-12 columns first last" style="Margin:0 auto;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0 auto;padding:0;padding-bottom:30px;padding-left:30px;padding-right:30px;text-align:left;width:550px">
  182. <table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
  183. EOF;
  184. protected $listItem = <<<EOF
  185. <tr style="padding:0;text-align:left;vertical-align:top">
  186. <td style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left;width:15px;">
  187. <p class="text-left" style="Margin:0;Margin-bottom:10px;color:#777;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;padding-left:10px;text-align:left">%s</p>
  188. </td>
  189. <td style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left">
  190. <p class="text-left" style="Margin:0;Margin-bottom:10px;color:#555;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;padding-left:10px;text-align:left">%s</p>
  191. </td>
  192. <td class="expander" style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0!important;text-align:left;visibility:hidden;width:0"></td>
  193. </tr>
  194. EOF;
  195. protected $listEnd = <<<EOF
  196. </table>
  197. </th>
  198. </tr>
  199. </tbody>
  200. </table>
  201. EOF;
  202. protected $buttonGroup = <<<EOF
  203. <table class="spacer" style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
  204. <tbody>
  205. <tr style="padding:0;text-align:left;vertical-align:top">
  206. <td height="50px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:50px;font-weight:400;hyphens:auto;line-height:50px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">&#xA0;</td>
  207. </tr>
  208. </tbody>
  209. </table>
  210. <table align="center" class="row btn-group" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%%">
  211. <tbody>
  212. <tr style="padding:0;text-align:left;vertical-align:top">
  213. <th class="small-12 large-12 columns first last" style="Margin:0 auto;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0 auto;padding:0;padding-bottom:30px;padding-left:30px;padding-right:30px;text-align:left;width:550px">
  214. <table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
  215. <tr style="padding:0;text-align:left;vertical-align:top">
  216. <th style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left">
  217. <center data-parsed="" style="min-width:490px;width:100%%">
  218. <table class="button btn default primary float-center" style="Margin:0 0 30px 0;border-collapse:collapse;border-spacing:0;display:inline-block;float:none;margin:0 0 30px 0;margin-right:15px;max-height:40px;max-width:200px;padding:0;text-align:center;vertical-align:top;width:auto">
  219. <tr style="padding:0;text-align:left;vertical-align:top">
  220. <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
  221. <table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
  222. <tr style="padding:0;text-align:left;vertical-align:top">
  223. <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;background:%s;border:0 solid %s;border-collapse:collapse!important;color:#fefefe;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
  224. <a href="%s" style="Margin:0;border:0 solid %s;border-radius:2px;color:%s;display:inline-block;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:regular;line-height:1.3;margin:0;padding:10px 25px 10px 25px;text-align:left;outline:1px solid %s;text-decoration:none">%s</a>
  225. </td>
  226. </tr>
  227. </table>
  228. </td>
  229. </tr>
  230. </table>
  231. <table class="button btn default secondary float-center" style="Margin:0 0 30px 0;border-collapse:collapse;border-spacing:0;display:inline-block;float:none;margin:0 0 30px 0;max-height:40px;max-width:200px;padding:0;text-align:center;vertical-align:top;width:auto">
  232. <tr style="padding:0;text-align:left;vertical-align:top">
  233. <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
  234. <table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
  235. <tr style="padding:0;text-align:left;vertical-align:top">
  236. <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;background:#777;border:0 solid #777;border-collapse:collapse!important;color:#fefefe;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
  237. <a href="%s" style="Margin:0;background-color:#fff;border:0 solid #777;border-radius:2px;color:#6C6C6C!important;display:inline-block;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:regular;line-height:1.3;margin:0;outline:1px solid #CBCBCB;padding:10px 25px 10px 25px;text-align:left;text-decoration:none">%s</a>
  238. </td>
  239. </tr>
  240. </table>
  241. </td>
  242. </tr>
  243. </table>
  244. </center>
  245. </th>
  246. <th class="expander" style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0!important;text-align:left;visibility:hidden;width:0"></th>
  247. </tr>
  248. </table>
  249. </th>
  250. </tr>
  251. </tbody>
  252. </table>
  253. EOF;
  254. protected $button = <<<EOF
  255. <table class="spacer" style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
  256. <tbody>
  257. <tr style="padding:0;text-align:left;vertical-align:top">
  258. <td height="50px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:50px;font-weight:400;hyphens:auto;line-height:50px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">&#xA0;</td>
  259. </tr>
  260. </tbody>
  261. </table>
  262. <table align="center" class="row btn-group" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%%">
  263. <tbody>
  264. <tr style="padding:0;text-align:left;vertical-align:top">
  265. <th class="small-12 large-12 columns first last" style="Margin:0 auto;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0 auto;padding:0;padding-bottom:30px;padding-left:30px;padding-right:30px;text-align:left;width:550px">
  266. <table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
  267. <tr style="padding:0;text-align:left;vertical-align:top">
  268. <th style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left">
  269. <center data-parsed="" style="min-width:490px;width:100%%">
  270. <table class="button btn default primary float-center" style="Margin:0;border-collapse:collapse;border-spacing:0;display:inline-block;float:none;margin:0;max-height:40px;padding:0;text-align:center;vertical-align:top;width:auto">
  271. <tr style="padding:0;text-align:left;vertical-align:top">
  272. <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
  273. <table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
  274. <tr style="padding:0;text-align:left;vertical-align:top">
  275. <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;background:%s;border:0 solid %s;border-collapse:collapse!important;color:#fefefe;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
  276. <a href="%s" style="Margin:0;border:0 solid %s;border-radius:2px;color:%s;display:inline-block;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:regular;line-height:1.3;margin:0;padding:10px 25px 10px 25px;text-align:left;outline:1px solid %s;text-decoration:none">%s</a>
  277. </td>
  278. </tr>
  279. </table>
  280. </td>
  281. </tr>
  282. </table>
  283. </center>
  284. </th>
  285. <th class="expander" style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0!important;text-align:left;visibility:hidden;width:0"></th>
  286. </tr>
  287. </table>
  288. </th>
  289. </tr>
  290. </tbody>
  291. </table>
  292. EOF;
  293. protected $bodyEnd = <<<EOF
  294. </td>
  295. </tr>
  296. </tbody>
  297. </table>
  298. </td>
  299. </tr>
  300. </table>
  301. EOF;
  302. protected $footer = <<<EOF
  303. <table class="spacer float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%">
  304. <tbody>
  305. <tr style="padding:0;text-align:left;vertical-align:top">
  306. <td height="60px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:60px;font-weight:400;hyphens:auto;line-height:60px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">&#xA0;</td>
  307. </tr>
  308. </tbody>
  309. </table>
  310. <table align="center" class="wrapper footer float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%">
  311. <tr style="padding:0;text-align:left;vertical-align:top">
  312. <td class="wrapper-inner" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
  313. <center data-parsed="" style="min-width:580px;width:100%%">
  314. <table class="spacer float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%">
  315. <tbody>
  316. <tr style="padding:0;text-align:left;vertical-align:top">
  317. <td height="15px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:15px;font-weight:400;hyphens:auto;line-height:15px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">&#xA0;</td>
  318. </tr>
  319. </tbody>
  320. </table>
  321. <p class="text-center float-center" align="center" style="Margin:0;Margin-bottom:10px;color:#C8C8C8;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:12px;font-weight:400;line-height:16px;margin:0;margin-bottom:10px;padding:0;text-align:center">%s</p>
  322. </center>
  323. </td>
  324. </tr>
  325. </table>
  326. EOF;
  327. /**
  328. * @param Defaults $themingDefaults
  329. * @param IURLGenerator $urlGenerator
  330. * @param IL10N $l10n
  331. * @param string $emailId
  332. * @param array $data
  333. */
  334. public function __construct(Defaults $themingDefaults,
  335. IURLGenerator $urlGenerator,
  336. IL10N $l10n,
  337. $emailId,
  338. array $data) {
  339. $this->themingDefaults = $themingDefaults;
  340. $this->urlGenerator = $urlGenerator;
  341. $this->l10n = $l10n;
  342. $this->htmlBody .= $this->head;
  343. $this->emailId = $emailId;
  344. $this->data = $data;
  345. }
  346. /**
  347. * Sets the subject of the email
  348. *
  349. * @param string $subject
  350. */
  351. public function setSubject(string $subject) {
  352. $this->subject = $subject;
  353. }
  354. /**
  355. * Adds a header to the email
  356. */
  357. public function addHeader() {
  358. if ($this->headerAdded) {
  359. return;
  360. }
  361. $this->headerAdded = true;
  362. $logoUrl = $this->urlGenerator->getAbsoluteURL($this->themingDefaults->getLogo(false));
  363. $this->htmlBody .= vsprintf($this->header, [$this->themingDefaults->getColorPrimary(), $logoUrl, $this->themingDefaults->getName()]);
  364. }
  365. /**
  366. * Adds a heading to the email
  367. *
  368. * @param string $title
  369. * @param string|bool $plainTitle Title that is used in the plain text email
  370. * if empty the $title is used, if false none will be used
  371. */
  372. public function addHeading(string $title, $plainTitle = '') {
  373. if ($this->footerAdded) {
  374. return;
  375. }
  376. if ($plainTitle === '') {
  377. $plainTitle = $title;
  378. }
  379. $this->htmlBody .= vsprintf($this->heading, [htmlspecialchars($title)]);
  380. if ($plainTitle !== false) {
  381. $this->plainBody .= $plainTitle . PHP_EOL . PHP_EOL;
  382. }
  383. }
  384. /**
  385. * Open the HTML body when it is not already
  386. */
  387. protected function ensureBodyIsOpened() {
  388. if ($this->bodyOpened) {
  389. return;
  390. }
  391. $this->htmlBody .= $this->bodyBegin;
  392. $this->bodyOpened = true;
  393. }
  394. /**
  395. * Adds a paragraph to the body of the email
  396. *
  397. * @param string $text Note: When $plainText falls back to this, HTML is automatically escaped in the HTML email
  398. * @param string|bool $plainText Text that is used in the plain text email
  399. * if empty the $text is used, if false none will be used
  400. */
  401. public function addBodyText(string $text, $plainText = '') {
  402. if ($this->footerAdded) {
  403. return;
  404. }
  405. if ($plainText === '') {
  406. $plainText = $text;
  407. $text = htmlspecialchars($text);
  408. }
  409. $this->ensureBodyIsOpened();
  410. $this->htmlBody .= vsprintf($this->bodyText, [$text]);
  411. if ($plainText !== false) {
  412. $this->plainBody .= $plainText . PHP_EOL . PHP_EOL;
  413. }
  414. }
  415. /**
  416. * Adds a list item to the body of the email
  417. *
  418. * @param string $text Note: When $plainText falls back to this, HTML is automatically escaped in the HTML email
  419. * @param string $metaInfo Note: When $plainMetaInfo falls back to this, HTML is automatically escaped in the HTML email
  420. * @param string $icon Absolute path, must be 16*16 pixels
  421. * @param string|bool $plainText Text that is used in the plain text email
  422. * if empty the $text is used, if false none will be used
  423. * @param string|bool $plainMetaInfo Meta info that is used in the plain text email
  424. * if empty the $metaInfo is used, if false none will be used
  425. * @since 12.0.0
  426. */
  427. public function addBodyListItem(string $text, string $metaInfo = '', string $icon = '', $plainText = '', $plainMetaInfo = '') {
  428. $this->ensureBodyListOpened();
  429. if ($plainText === '') {
  430. $plainText = $text;
  431. $text = htmlspecialchars($text);
  432. }
  433. if ($plainMetaInfo === '') {
  434. $plainMetaInfo = $metaInfo;
  435. $metaInfo = htmlspecialchars($metaInfo);
  436. }
  437. $htmlText = $text;
  438. if ($metaInfo) {
  439. $htmlText = '<em style="color:#777;">' . $metaInfo . '</em><br>' . $htmlText;
  440. }
  441. if ($icon !== '') {
  442. $icon = '<img src="' . htmlspecialchars($icon) . '" alt="&bull;">';
  443. } else {
  444. $icon = '&bull;';
  445. }
  446. $this->htmlBody .= vsprintf($this->listItem, [$icon, $htmlText]);
  447. if ($plainText !== false) {
  448. $this->plainBody .= ' * ' . $plainText;
  449. if ($plainMetaInfo !== false) {
  450. $this->plainBody .= ' (' . $plainMetaInfo . ')';
  451. }
  452. $this->plainBody .= PHP_EOL;
  453. }
  454. }
  455. protected function ensureBodyListOpened() {
  456. if ($this->bodyListOpened) {
  457. return;
  458. }
  459. $this->ensureBodyIsOpened();
  460. $this->bodyListOpened = true;
  461. $this->htmlBody .= $this->listBegin;
  462. }
  463. protected function ensureBodyListClosed() {
  464. if (!$this->bodyListOpened) {
  465. return;
  466. }
  467. $this->bodyListOpened = false;
  468. $this->htmlBody .= $this->listEnd;
  469. }
  470. /**
  471. * Adds a button group of two buttons to the body of the email
  472. *
  473. * @param string $textLeft Text of left button; Note: When $plainTextLeft falls back to this, HTML is automatically escaped in the HTML email
  474. * @param string $urlLeft URL of left button
  475. * @param string $textRight Text of right button; Note: When $plainTextRight falls back to this, HTML is automatically escaped in the HTML email
  476. * @param string $urlRight URL of right button
  477. * @param string $plainTextLeft Text of left button that is used in the plain text version - if unset the $textLeft is used
  478. * @param string $plainTextRight Text of right button that is used in the plain text version - if unset the $textRight is used
  479. */
  480. public function addBodyButtonGroup(string $textLeft,
  481. string $urlLeft,
  482. string $textRight,
  483. string $urlRight,
  484. string $plainTextLeft = '',
  485. string $plainTextRight = '') {
  486. if ($this->footerAdded) {
  487. return;
  488. }
  489. if ($plainTextLeft === '') {
  490. $plainTextLeft = $textLeft;
  491. $textLeft = htmlspecialchars($textLeft);
  492. }
  493. if ($plainTextRight === '') {
  494. $plainTextRight = $textRight;
  495. $textRight = htmlspecialchars($textRight);
  496. }
  497. $this->ensureBodyIsOpened();
  498. $this->ensureBodyListClosed();
  499. $color = $this->themingDefaults->getColorPrimary();
  500. $textColor = $this->themingDefaults->getTextColorPrimary();
  501. $this->htmlBody .= vsprintf($this->buttonGroup, [$color, $color, $urlLeft, $color, $textColor, $textColor, $textLeft, $urlRight, $textRight]);
  502. $this->plainBody .= $plainTextLeft . ': ' . $urlLeft . PHP_EOL;
  503. $this->plainBody .= $plainTextRight . ': ' . $urlRight . PHP_EOL . PHP_EOL;
  504. }
  505. /**
  506. * Adds a button to the body of the email
  507. *
  508. * @param string $text Text of button; Note: When $plainText falls back to this, HTML is automatically escaped in the HTML email
  509. * @param string $url URL of button
  510. * @param string $plainText Text of button in plain text version
  511. * if empty the $text is used, if false none will be used
  512. *
  513. * @since 12.0.0
  514. */
  515. public function addBodyButton(string $text, string $url, $plainText = '') {
  516. if ($this->footerAdded) {
  517. return;
  518. }
  519. $this->ensureBodyIsOpened();
  520. $this->ensureBodyListClosed();
  521. if ($plainText === '') {
  522. $plainText = $text;
  523. $text = htmlspecialchars($text);
  524. }
  525. $color = $this->themingDefaults->getColorPrimary();
  526. $textColor = $this->themingDefaults->getTextColorPrimary();
  527. $this->htmlBody .= vsprintf($this->button, [$color, $color, $url, $color, $textColor, $textColor, $text]);
  528. if ($plainText !== false) {
  529. $this->plainBody .= $plainText . ': ';
  530. }
  531. $this->plainBody .= $url . PHP_EOL;
  532. }
  533. /**
  534. * Close the HTML body when it is open
  535. */
  536. protected function ensureBodyIsClosed() {
  537. if (!$this->bodyOpened) {
  538. return;
  539. }
  540. $this->ensureBodyListClosed();
  541. $this->htmlBody .= $this->bodyEnd;
  542. $this->bodyOpened = false;
  543. }
  544. /**
  545. * Adds a logo and a text to the footer. <br> in the text will be replaced by new lines in the plain text email
  546. *
  547. * @param string $text If the text is empty the default "Name - Slogan<br>This is an automatically sent email" will be used
  548. */
  549. public function addFooter(string $text = '') {
  550. if($text === '') {
  551. $text = $this->themingDefaults->getName() . ' - ' . $this->themingDefaults->getSlogan() . '<br>' . $this->l10n->t('This is an automatically sent email, please do not reply.');
  552. }
  553. if ($this->footerAdded) {
  554. return;
  555. }
  556. $this->footerAdded = true;
  557. $this->ensureBodyIsClosed();
  558. $this->htmlBody .= vsprintf($this->footer, [$text]);
  559. $this->htmlBody .= $this->tail;
  560. $this->plainBody .= PHP_EOL . '-- ' . PHP_EOL;
  561. $this->plainBody .= str_replace('<br>', PHP_EOL, $text);
  562. }
  563. /**
  564. * Returns the rendered email subject as string
  565. *
  566. * @return string
  567. */
  568. public function renderSubject(): string {
  569. return $this->subject;
  570. }
  571. /**
  572. * Returns the rendered HTML email as string
  573. *
  574. * @return string
  575. */
  576. public function renderHtml(): string {
  577. if (!$this->footerAdded) {
  578. $this->footerAdded = true;
  579. $this->ensureBodyIsClosed();
  580. $this->htmlBody .= $this->tail;
  581. }
  582. return $this->htmlBody;
  583. }
  584. /**
  585. * Returns the rendered plain text email as string
  586. *
  587. * @return string
  588. */
  589. public function renderText(): string {
  590. if (!$this->footerAdded) {
  591. $this->footerAdded = true;
  592. $this->ensureBodyIsClosed();
  593. $this->htmlBody .= $this->tail;
  594. }
  595. return $this->plainBody;
  596. }
  597. }