reply-to working
This commit is contained in:
@@ -51,7 +51,7 @@ class Messages extends Controller {
|
||||
|
||||
// send mail confirmation link
|
||||
var e = new sugoi.mail.Mail();
|
||||
e.setSender(App.config.get("default_email"));
|
||||
e.setSender(App.config.get("default_email"), t._("Cagette.net"));
|
||||
e.setSubject(subject);
|
||||
|
||||
var replyTo = form.getValueOf("senderMail");
|
||||
@@ -62,8 +62,6 @@ class Messages extends Controller {
|
||||
for (x in mails)
|
||||
e.addRecipient(x);
|
||||
|
||||
// sender : default email ( explicitly tells that the server send an email on behalf of the user )
|
||||
// e.setHeader("Sender", App.config.get("default_email"));
|
||||
var text:String = form.getValueOf("text");
|
||||
var html = app.processTemplate("mail/message.mtt", {text: text, group: app.user.amap, list: getListName(listId)});
|
||||
e.setHtmlBody(html);
|
||||
@@ -84,6 +82,8 @@ class Messages extends Controller {
|
||||
lm.insert();
|
||||
|
||||
throw Ok("/messages", t._("The message has been sent"));
|
||||
} else {
|
||||
App.log('Administrator #${app.user.id} <${senderName}> prepares sending an email from choices list');
|
||||
}
|
||||
|
||||
view.form = form;
|
||||
|
||||
+70
-63
@@ -1,45 +1,53 @@
|
||||
package sugoi.mail;
|
||||
|
||||
using Lambda;
|
||||
|
||||
class Mail implements IMail
|
||||
{
|
||||
|
||||
public var title : String;
|
||||
public var htmlBody : String;
|
||||
public var textBody : String;
|
||||
var headers : Map<String,String>;
|
||||
var sender : {name:String,email:String,?userId:Int};
|
||||
var recipients : Array<{name:String,email:String,?userId:Int}>;
|
||||
|
||||
|
||||
|
||||
class Mail implements IMail {
|
||||
public var title:String;
|
||||
public var htmlBody:String;
|
||||
public var textBody:String;
|
||||
|
||||
var headers:Map<String, String>;
|
||||
var sender:{name:String, email:String, ?userId:Int};
|
||||
var recipients:Array<{name:String, email:String, ?userId:Int}>;
|
||||
|
||||
static public function fromString(name:String, email:String) {
|
||||
if (name == null)
|
||||
return email;
|
||||
else {
|
||||
var finalName = thx.text.Diactrics.clean(name);
|
||||
return '${finalName} <${email}>';
|
||||
}
|
||||
}
|
||||
|
||||
public function new() {
|
||||
recipients = [];
|
||||
headers = new Map();
|
||||
}
|
||||
|
||||
public function getRecipients(){
|
||||
|
||||
public function getRecipients() {
|
||||
return recipients;
|
||||
}
|
||||
|
||||
public function setSender(email, ?name,?userId) {
|
||||
if(!isValid(email)) throw "invalid sender email : \""+email+"\"";
|
||||
|
||||
sender = {name:name,email:email,userId:userId};
|
||||
|
||||
public function setSender(email, ?name, ?userId) {
|
||||
if (!isValid(email))
|
||||
throw "invalid sender email : \"" + email + "\"";
|
||||
|
||||
sender = {name: name, email: email, userId: userId};
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public function setReplyTo(email, ?name) {
|
||||
if(!isValid(email)) throw "invalid reply-to email : \""+email+"\"";
|
||||
|
||||
setHeader("Reply-To","<"+email+">"+(name==null?"":name));
|
||||
if (!isValid(email))
|
||||
throw "invalid reply-to email : \"" + email + "\"";
|
||||
setHeader("Reply-To", fromString(name, email));
|
||||
}
|
||||
|
||||
|
||||
public function setSubject(s:String) {
|
||||
title = s;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* can add one or more recipient
|
||||
* @param email
|
||||
@@ -47,11 +55,12 @@ class Mail implements IMail
|
||||
* @param ?userId
|
||||
*/
|
||||
public function addRecipient(email:String, ?name:String, ?userId:Int) {
|
||||
if(!isValid(email)) throw "invalid recipient \""+email+"\"";
|
||||
recipients.push( {email:email, name:name, userId:userId } );
|
||||
if (!isValid(email))
|
||||
throw "invalid recipient \"" + email + "\"";
|
||||
recipients.push({email: email, name: name, userId: userId});
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* alias to addRecipient()
|
||||
* @param email
|
||||
@@ -62,24 +71,24 @@ class Mail implements IMail
|
||||
addRecipient(email, name, userId);
|
||||
return this;
|
||||
}
|
||||
|
||||
public static function isValid( addr : String ){
|
||||
|
||||
public static function isValid(addr:String) {
|
||||
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;
|
||||
return addr != null && reg.match(addr);
|
||||
}
|
||||
|
||||
|
||||
public function setHeader(k:String, v:String) {
|
||||
headers.set(k, v);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* generate a custom key for transactionnal emails, valid during the current day
|
||||
*/
|
||||
public function getKey() {
|
||||
return haxe.crypto.Md5.encode(App.config.get("key")+recipients[0].email+(Date.now().getDate())).substr(0,12);
|
||||
return haxe.crypto.Md5.encode(App.config.get("key") + recipients[0].email + (Date.now().getDate())).substr(0, 12);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* render html from a template + vars
|
||||
* @param tpl A Template path
|
||||
@@ -88,7 +97,8 @@ class Mail implements IMail
|
||||
public function setHtmlBodyWithTemplate(tpl, ctx:Dynamic) {
|
||||
var app = App.current;
|
||||
var tpl = app.loadTemplate(tpl);
|
||||
if( ctx == null ) ctx = { };
|
||||
if (ctx == null)
|
||||
ctx = {};
|
||||
ctx.HOST = App.config.HOST;
|
||||
ctx.key = getKey();
|
||||
ctx.senderName = sender.name;
|
||||
@@ -98,28 +108,27 @@ class Mail implements IMail
|
||||
ctx.recipients = recipients;
|
||||
CSSInlining(ctx);
|
||||
htmlBody = tpl.execute(ctx);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function setHtmlBody(s) {
|
||||
htmlBody = s;
|
||||
return this;
|
||||
}
|
||||
|
||||
public function setTextBodyWithTemplate(tpl, ctx:Dynamic) {
|
||||
|
||||
public function setTextBodyWithTemplate(tpl, ctx:Dynamic) {
|
||||
var app = App.current;
|
||||
var tpl = app.loadTemplate(tpl);
|
||||
if( ctx == null ) ctx = { };
|
||||
if (ctx == null)
|
||||
ctx = {};
|
||||
ctx.HOST = App.config.HOST;
|
||||
ctx.key = getKey();
|
||||
textBody = tpl.execute(ctx);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
function CSSInlining(ctx) {
|
||||
// CSS inlining
|
||||
var css : Map<String,Array<String>> = new Map();
|
||||
var css:Map<String, Array<String>> = new Map();
|
||||
ctx.addStyle = function(sel:String, style:String) {
|
||||
sel = sel.toLowerCase();
|
||||
if (css.exists(sel))
|
||||
@@ -130,11 +139,11 @@ class Mail implements IMail
|
||||
}
|
||||
var applyStyleRec = null;
|
||||
applyStyleRec = function(x:Xml) {
|
||||
if (x.nodeType==Xml.Element) {
|
||||
if (x.nodeType == Xml.Element) {
|
||||
var name = x.nodeName.toLowerCase();
|
||||
if( css.exists(name) )
|
||||
if (x.get("style")!=null)
|
||||
x.set("style", x.get("style")+";"+css.get(name).join(";"));
|
||||
if (css.exists(name))
|
||||
if (x.get("style") != null)
|
||||
x.set("style", x.get("style") + ";" + css.get(name).join(";"));
|
||||
else
|
||||
x.set("style", css.get(name).join(";"));
|
||||
for (n in x)
|
||||
@@ -143,40 +152,38 @@ class Mail implements IMail
|
||||
}
|
||||
ctx.applyStyle = function(raw:String) {
|
||||
var x = Xml.parse(raw);
|
||||
for(n in x)
|
||||
for (n in x)
|
||||
applyStyleRec(n);
|
||||
return x.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function getSubject(){
|
||||
|
||||
public function getSubject() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public function getTitle(){
|
||||
public function getTitle() {
|
||||
return getSubject();
|
||||
}
|
||||
|
||||
public function getHtmlBody(){
|
||||
|
||||
public function getHtmlBody() {
|
||||
return htmlBody;
|
||||
}
|
||||
|
||||
public function getTextBody(){
|
||||
|
||||
public function getTextBody() {
|
||||
return textBody;
|
||||
}
|
||||
|
||||
public function setTextBody(t){
|
||||
|
||||
public function setTextBody(t) {
|
||||
textBody = t;
|
||||
return this;
|
||||
}
|
||||
|
||||
public function getHeaders(){
|
||||
|
||||
public function getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public function getSender(){
|
||||
|
||||
public function getSender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,17 +40,13 @@ class SendEmailMailer implements IMailer {
|
||||
return mailer;
|
||||
}
|
||||
|
||||
private function fromString(name:String, email:String) {
|
||||
return (name == null) ? email : '${name} <${email}>';
|
||||
}
|
||||
|
||||
public function send(e:sugoi.mail.IMail, ?params:Dynamic, ?callback:MailerResult->Void) {
|
||||
var to:String;
|
||||
var bcc:String;
|
||||
|
||||
var recipientCounts = e.getRecipients().length;
|
||||
if (recipientCounts > 1) {
|
||||
to = fromString(e.getSender().name, e.getSender().email);
|
||||
to = sugoi.mail.Mail.fromString(e.getSender().name, e.getSender().email);
|
||||
bcc = [for (i in e.getRecipients()) i.email].join(",");
|
||||
App.log('recipients has been transformed to ${recipientCounts} bcc');
|
||||
App.log(bcc);
|
||||
@@ -72,26 +68,35 @@ class SendEmailMailer implements IMailer {
|
||||
"-o",
|
||||
"message-format=html",
|
||||
"-o",
|
||||
"X-Mailer=CagettePei",
|
||||
"message-header=X-Mailer: CagettePei",
|
||||
"-f",
|
||||
fromString(e.getSender().name, e.getSender().email),
|
||||
sugoi.mail.Mail.fromString(e.getSender().name, e.getSender().email),
|
||||
"-t",
|
||||
to,
|
||||
"-bcc",
|
||||
bcc,
|
||||
"-u",
|
||||
e.getSubject(),
|
||||
"-m",
|
||||
'<html>${e.getHtmlBody()}</html>',
|
||||
];
|
||||
|
||||
// FIME: deal with replyTo
|
||||
if (e.getHeaders().exists("Reply-To")) {
|
||||
var replyTo = e.getHeaders()["Reply-To"];
|
||||
App.log('replyTo "$replyTo" detected');
|
||||
args.push("-o");
|
||||
args.push('message-header=Reply-To: ${replyTo}');
|
||||
}
|
||||
|
||||
args.push("-m");
|
||||
args.push('<html>${e.getHtmlBody()}</html>');
|
||||
|
||||
// if (App.config.DEBUG)
|
||||
// App.log('args=${args.join(" ")}');
|
||||
|
||||
var exitCode = Sys.command("sendemail", args);
|
||||
// var exitCode = 0;
|
||||
|
||||
var summary = 'email from="${fromString(e.getSender().name, e.getSender().email)}"> subject=<${e.getSubject()}>';
|
||||
var summary = 'email from="${sugoi.mail.Mail.fromString(e.getSender().name, e.getSender().email)}" subject=<${e.getSubject()}>';
|
||||
if (exitCode == 0)
|
||||
App.log('$summary successfully sent');
|
||||
else
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
package sugoi.mail;
|
||||
import tink.core.Future;
|
||||
import tink.core.Noise;
|
||||
import sugoi.mail.IMailer;
|
||||
import smtpmailer.Address;
|
||||
|
||||
/**
|
||||
* Send emails thru SMTP by using ben merckx's library
|
||||
* @ref https://github.com/benmerckx/smtpmailer
|
||||
*/
|
||||
class SmtpMailer implements IMailer
|
||||
{
|
||||
var m : smtpmailer.SmtpMailer;
|
||||
|
||||
public function new(){}
|
||||
|
||||
public function init(?conf:{smtp_host:String,smtp_port:Int,smtp_user:String,smtp_pass:String}) :IMailer
|
||||
{
|
||||
m = new smtpmailer.SmtpMailer({
|
||||
host: conf.smtp_host,
|
||||
port: conf.smtp_port,
|
||||
auth: {
|
||||
username: conf.smtp_user,
|
||||
password: conf.smtp_pass
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public function send(e:sugoi.mail.IMail,?params:Dynamic,?callback:MailerResult->Void)
|
||||
{
|
||||
var surprise = m.send({
|
||||
subject: e.getSubject(),
|
||||
/*from: e.getSender().email,
|
||||
to: Lambda.array(Lambda.map(e.getRecipients(), function(x) return smtpmailer.Address.ofString(x.email) )),
|
||||
//headers : e.getHeaders(),*/
|
||||
from: new Address({address:e.getSender().email}),
|
||||
to: Lambda.array(Lambda.map(e.getRecipients(), function(x) return new Address({address:x.email}) )),
|
||||
headers : e.getHeaders(),
|
||||
content: {
|
||||
text: e.getTextBody(),
|
||||
html: e.getHtmlBody()
|
||||
}/*,
|
||||
attachments: []*/
|
||||
});
|
||||
|
||||
|
||||
if (callback != null){
|
||||
|
||||
surprise.handle(function(s){
|
||||
|
||||
var map = new MailerResult();
|
||||
|
||||
switch(s){
|
||||
case Success(_):
|
||||
map.set("*",Success(Sent));
|
||||
|
||||
case Failure(e):
|
||||
map.set("*",Failure(GenericError(e)));
|
||||
}
|
||||
|
||||
callback(map);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user