EMailTemplate.php 32 KB

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