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.

189 lines
4.2 KiB

  1. package sugoi.mail;
  2. using Lambda;
  3. class Mail implements IMail {
  4. public var title:String;
  5. public var htmlBody:String;
  6. public var textBody:String;
  7. var headers:Map<String, String>;
  8. var sender:{name:String, email:String, ?userId:Int};
  9. var recipients:Array<{name:String, email:String, ?userId:Int}>;
  10. static public function fromString(name:String, email:String) {
  11. if (name == null)
  12. return email;
  13. else {
  14. var finalName = thx.text.Diactrics.clean(name);
  15. return '${finalName} <${email}>';
  16. }
  17. }
  18. public function new() {
  19. recipients = [];
  20. headers = new Map();
  21. }
  22. public function getRecipients() {
  23. return recipients;
  24. }
  25. public function setSender(email, ?name, ?userId) {
  26. if (!isValid(email))
  27. throw "invalid sender email : \"" + email + "\"";
  28. sender = {name: name, email: email, userId: userId};
  29. return this;
  30. }
  31. public function setReplyTo(email, ?name) {
  32. if (!isValid(email))
  33. throw "invalid reply-to email : \"" + email + "\"";
  34. setHeader("Reply-To", fromString(name, email));
  35. }
  36. public function setSubject(s:String) {
  37. title = s;
  38. return this;
  39. }
  40. /**
  41. * can add one or more recipient
  42. * @param email
  43. * @param ?name
  44. * @param ?userId
  45. */
  46. public function addRecipient(email:String, ?name:String, ?userId:Int) {
  47. if (!isValid(email))
  48. throw "invalid recipient \"" + email + "\"";
  49. recipients.push({email: email, name: name, userId: userId});
  50. return this;
  51. }
  52. /**
  53. * alias to addRecipient()
  54. * @param email
  55. * @param ?name
  56. * @param ?userId
  57. */
  58. public function setRecipient(email:String, ?name:String, ?userId:Int) {
  59. addRecipient(email, name, userId);
  60. return this;
  61. }
  62. public static function isValid(addr:String) {
  63. var reg = ~/^[^()<>@,;:\\"\[\]\s[:cntrl:]]+@[A-Z0-9][A-Z0-9-]*(\.[A-Z0-9][A-Z0-9-]*)*\.(xn--[A-Z0-9]+|[A-Z]{2,8})$/i;
  64. return addr != null && reg.match(addr);
  65. }
  66. public function setHeader(k:String, v:String) {
  67. headers.set(k, v);
  68. return this;
  69. }
  70. /**
  71. * generate a custom key for transactionnal emails, valid during the current day
  72. */
  73. public function getKey() {
  74. return haxe.crypto.Md5.encode(App.config.get("key") + recipients[0].email + (Date.now().getDate())).substr(0, 12);
  75. }
  76. /**
  77. * render html from a template + vars
  78. * @param tpl A Template path
  79. * @param ctx Vars to send to template
  80. */
  81. public function setHtmlBodyWithTemplate(tpl, ctx:Dynamic) {
  82. var app = App.current;
  83. var tpl = app.loadTemplate(tpl);
  84. if (ctx == null)
  85. ctx = {};
  86. ctx.HOST = App.config.HOST;
  87. ctx.key = getKey();
  88. ctx.senderName = sender.name;
  89. ctx.senderEmail = sender.email;
  90. ctx.recipientName = recipients[0].name;
  91. ctx.recipientEmail = recipients[0].email;
  92. ctx.recipients = recipients;
  93. CSSInlining(ctx);
  94. htmlBody = tpl.execute(ctx);
  95. }
  96. public function setHtmlBody(s) {
  97. htmlBody = s;
  98. return this;
  99. }
  100. public function setTextBodyWithTemplate(tpl, ctx:Dynamic) {
  101. var app = App.current;
  102. var tpl = app.loadTemplate(tpl);
  103. if (ctx == null)
  104. ctx = {};
  105. ctx.HOST = App.config.HOST;
  106. ctx.key = getKey();
  107. textBody = tpl.execute(ctx);
  108. return this;
  109. }
  110. function CSSInlining(ctx) {
  111. // CSS inlining
  112. var css:Map<String, Array<String>> = new Map();
  113. ctx.addStyle = function(sel:String, style:String) {
  114. sel = sel.toLowerCase();
  115. if (css.exists(sel))
  116. css.set(sel, css.get(sel).concat(style.split(";")));
  117. else
  118. css.set(sel, style.split(";"));
  119. return "";
  120. }
  121. var applyStyleRec = null;
  122. applyStyleRec = function(x:Xml) {
  123. if (x.nodeType == Xml.Element) {
  124. var name = x.nodeName.toLowerCase();
  125. if (css.exists(name))
  126. if (x.get("style") != null)
  127. x.set("style", x.get("style") + ";" + css.get(name).join(";"));
  128. else
  129. x.set("style", css.get(name).join(";"));
  130. for (n in x)
  131. applyStyleRec(n);
  132. }
  133. }
  134. ctx.applyStyle = function(raw:String) {
  135. var x = Xml.parse(raw);
  136. for (n in x)
  137. applyStyleRec(n);
  138. return x.toString();
  139. }
  140. }
  141. public function getSubject() {
  142. return title;
  143. }
  144. public function getTitle() {
  145. return getSubject();
  146. }
  147. public function getHtmlBody() {
  148. return htmlBody;
  149. }
  150. public function getTextBody() {
  151. return textBody;
  152. }
  153. public function setTextBody(t) {
  154. textBody = t;
  155. return this;
  156. }
  157. public function getHeaders() {
  158. return headers;
  159. }
  160. public function getSender() {
  161. return sender;
  162. }
  163. }