reply-to working
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
-lib tink_streams:0.2.1
|
-lib tink_streams:0.2.1
|
||||||
-lib tink_syntaxhub:0.4.3
|
-lib tink_syntaxhub:0.4.3
|
||||||
-lib tink_typecrawler:0.7.0
|
-lib tink_typecrawler:0.7.0
|
||||||
|
-lib thx.text:0.2.1
|
||||||
|
|
||||||
## GIT
|
## GIT
|
||||||
# -lib sugoi:git:https://git.artcode.re/cagetters/sugoi.git
|
# -lib sugoi:git:https://git.artcode.re/cagetters/sugoi.git
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<div class="article">
|
<div class="article">
|
||||||
<h3>::_("Send an e-mail")::</h3>
|
<h3>::_("Send an e-mail")::</h3>
|
||||||
|
|
||||||
::raw form::
|
::raw form::
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class Messages extends Controller {
|
|||||||
|
|
||||||
// send mail confirmation link
|
// send mail confirmation link
|
||||||
var e = new sugoi.mail.Mail();
|
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);
|
e.setSubject(subject);
|
||||||
|
|
||||||
var replyTo = form.getValueOf("senderMail");
|
var replyTo = form.getValueOf("senderMail");
|
||||||
@@ -62,8 +62,6 @@ class Messages extends Controller {
|
|||||||
for (x in mails)
|
for (x in mails)
|
||||||
e.addRecipient(x);
|
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 text:String = form.getValueOf("text");
|
||||||
var html = app.processTemplate("mail/message.mtt", {text: text, group: app.user.amap, list: getListName(listId)});
|
var html = app.processTemplate("mail/message.mtt", {text: text, group: app.user.amap, list: getListName(listId)});
|
||||||
e.setHtmlBody(html);
|
e.setHtmlBody(html);
|
||||||
@@ -84,6 +82,8 @@ class Messages extends Controller {
|
|||||||
lm.insert();
|
lm.insert();
|
||||||
|
|
||||||
throw Ok("/messages", t._("The message has been sent"));
|
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;
|
view.form = form;
|
||||||
|
|||||||
+70
-63
@@ -1,45 +1,53 @@
|
|||||||
package sugoi.mail;
|
package sugoi.mail;
|
||||||
|
|
||||||
using Lambda;
|
using Lambda;
|
||||||
|
|
||||||
class Mail implements IMail
|
class Mail implements IMail {
|
||||||
{
|
public var title:String;
|
||||||
|
public var htmlBody:String;
|
||||||
public var title : String;
|
public var textBody:String;
|
||||||
public var htmlBody : String;
|
|
||||||
public var textBody : String;
|
var headers:Map<String, String>;
|
||||||
var headers : Map<String,String>;
|
var sender:{name:String, email:String, ?userId:Int};
|
||||||
var sender : {name:String,email:String,?userId:Int};
|
var recipients:Array<{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() {
|
public function new() {
|
||||||
recipients = [];
|
recipients = [];
|
||||||
headers = new Map();
|
headers = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRecipients(){
|
public function getRecipients() {
|
||||||
return recipients;
|
return recipients;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setSender(email, ?name,?userId) {
|
public function setSender(email, ?name, ?userId) {
|
||||||
if(!isValid(email)) throw "invalid sender email : \""+email+"\"";
|
if (!isValid(email))
|
||||||
|
throw "invalid sender email : \"" + email + "\"";
|
||||||
sender = {name:name,email:email,userId:userId};
|
|
||||||
|
sender = {name: name, email: email, userId: userId};
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setReplyTo(email, ?name) {
|
public function setReplyTo(email, ?name) {
|
||||||
if(!isValid(email)) throw "invalid reply-to email : \""+email+"\"";
|
if (!isValid(email))
|
||||||
|
throw "invalid reply-to email : \"" + email + "\"";
|
||||||
setHeader("Reply-To","<"+email+">"+(name==null?"":name));
|
setHeader("Reply-To", fromString(name, email));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setSubject(s:String) {
|
public function setSubject(s:String) {
|
||||||
title = s;
|
title = s;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* can add one or more recipient
|
* can add one or more recipient
|
||||||
* @param email
|
* @param email
|
||||||
@@ -47,11 +55,12 @@ class Mail implements IMail
|
|||||||
* @param ?userId
|
* @param ?userId
|
||||||
*/
|
*/
|
||||||
public function addRecipient(email:String, ?name:String, ?userId:Int) {
|
public function addRecipient(email:String, ?name:String, ?userId:Int) {
|
||||||
if(!isValid(email)) throw "invalid recipient \""+email+"\"";
|
if (!isValid(email))
|
||||||
recipients.push( {email:email, name:name, userId:userId } );
|
throw "invalid recipient \"" + email + "\"";
|
||||||
|
recipients.push({email: email, name: name, userId: userId});
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* alias to addRecipient()
|
* alias to addRecipient()
|
||||||
* @param email
|
* @param email
|
||||||
@@ -62,24 +71,24 @@ class Mail implements IMail
|
|||||||
addRecipient(email, name, userId);
|
addRecipient(email, name, userId);
|
||||||
return this;
|
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;
|
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);
|
return addr != null && reg.match(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setHeader(k:String, v:String) {
|
public function setHeader(k:String, v:String) {
|
||||||
headers.set(k, v);
|
headers.set(k, v);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* generate a custom key for transactionnal emails, valid during the current day
|
* generate a custom key for transactionnal emails, valid during the current day
|
||||||
*/
|
*/
|
||||||
public function getKey() {
|
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
|
* render html from a template + vars
|
||||||
* @param tpl A Template path
|
* @param tpl A Template path
|
||||||
@@ -88,7 +97,8 @@ class Mail implements IMail
|
|||||||
public function setHtmlBodyWithTemplate(tpl, ctx:Dynamic) {
|
public function setHtmlBodyWithTemplate(tpl, ctx:Dynamic) {
|
||||||
var app = App.current;
|
var app = App.current;
|
||||||
var tpl = app.loadTemplate(tpl);
|
var tpl = app.loadTemplate(tpl);
|
||||||
if( ctx == null ) ctx = { };
|
if (ctx == null)
|
||||||
|
ctx = {};
|
||||||
ctx.HOST = App.config.HOST;
|
ctx.HOST = App.config.HOST;
|
||||||
ctx.key = getKey();
|
ctx.key = getKey();
|
||||||
ctx.senderName = sender.name;
|
ctx.senderName = sender.name;
|
||||||
@@ -98,28 +108,27 @@ class Mail implements IMail
|
|||||||
ctx.recipients = recipients;
|
ctx.recipients = recipients;
|
||||||
CSSInlining(ctx);
|
CSSInlining(ctx);
|
||||||
htmlBody = tpl.execute(ctx);
|
htmlBody = tpl.execute(ctx);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setHtmlBody(s) {
|
public function setHtmlBody(s) {
|
||||||
htmlBody = s;
|
htmlBody = s;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setTextBodyWithTemplate(tpl, ctx:Dynamic) {
|
public function setTextBodyWithTemplate(tpl, ctx:Dynamic) {
|
||||||
var app = App.current;
|
var app = App.current;
|
||||||
var tpl = app.loadTemplate(tpl);
|
var tpl = app.loadTemplate(tpl);
|
||||||
if( ctx == null ) ctx = { };
|
if (ctx == null)
|
||||||
|
ctx = {};
|
||||||
ctx.HOST = App.config.HOST;
|
ctx.HOST = App.config.HOST;
|
||||||
ctx.key = getKey();
|
ctx.key = getKey();
|
||||||
textBody = tpl.execute(ctx);
|
textBody = tpl.execute(ctx);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function CSSInlining(ctx) {
|
function CSSInlining(ctx) {
|
||||||
// CSS inlining
|
// 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) {
|
ctx.addStyle = function(sel:String, style:String) {
|
||||||
sel = sel.toLowerCase();
|
sel = sel.toLowerCase();
|
||||||
if (css.exists(sel))
|
if (css.exists(sel))
|
||||||
@@ -130,11 +139,11 @@ class Mail implements IMail
|
|||||||
}
|
}
|
||||||
var applyStyleRec = null;
|
var applyStyleRec = null;
|
||||||
applyStyleRec = function(x:Xml) {
|
applyStyleRec = function(x:Xml) {
|
||||||
if (x.nodeType==Xml.Element) {
|
if (x.nodeType == Xml.Element) {
|
||||||
var name = x.nodeName.toLowerCase();
|
var name = x.nodeName.toLowerCase();
|
||||||
if( css.exists(name) )
|
if (css.exists(name))
|
||||||
if (x.get("style")!=null)
|
if (x.get("style") != null)
|
||||||
x.set("style", x.get("style")+";"+css.get(name).join(";"));
|
x.set("style", x.get("style") + ";" + css.get(name).join(";"));
|
||||||
else
|
else
|
||||||
x.set("style", css.get(name).join(";"));
|
x.set("style", css.get(name).join(";"));
|
||||||
for (n in x)
|
for (n in x)
|
||||||
@@ -143,40 +152,38 @@ class Mail implements IMail
|
|||||||
}
|
}
|
||||||
ctx.applyStyle = function(raw:String) {
|
ctx.applyStyle = function(raw:String) {
|
||||||
var x = Xml.parse(raw);
|
var x = Xml.parse(raw);
|
||||||
for(n in x)
|
for (n in x)
|
||||||
applyStyleRec(n);
|
applyStyleRec(n);
|
||||||
return x.toString();
|
return x.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getSubject() {
|
||||||
public function getSubject(){
|
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTitle(){
|
public function getTitle() {
|
||||||
return getSubject();
|
return getSubject();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHtmlBody(){
|
public function getHtmlBody() {
|
||||||
return htmlBody;
|
return htmlBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTextBody(){
|
public function getTextBody() {
|
||||||
return textBody;
|
return textBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setTextBody(t){
|
public function setTextBody(t) {
|
||||||
textBody = t;
|
textBody = t;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHeaders(){
|
public function getHeaders() {
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSender(){
|
public function getSender() {
|
||||||
return sender;
|
return sender;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -40,17 +40,13 @@ class SendEmailMailer implements IMailer {
|
|||||||
return mailer;
|
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) {
|
public function send(e:sugoi.mail.IMail, ?params:Dynamic, ?callback:MailerResult->Void) {
|
||||||
var to:String;
|
var to:String;
|
||||||
var bcc:String;
|
var bcc:String;
|
||||||
|
|
||||||
var recipientCounts = e.getRecipients().length;
|
var recipientCounts = e.getRecipients().length;
|
||||||
if (recipientCounts > 1) {
|
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(",");
|
bcc = [for (i in e.getRecipients()) i.email].join(",");
|
||||||
App.log('recipients has been transformed to ${recipientCounts} bcc');
|
App.log('recipients has been transformed to ${recipientCounts} bcc');
|
||||||
App.log(bcc);
|
App.log(bcc);
|
||||||
@@ -72,26 +68,35 @@ class SendEmailMailer implements IMailer {
|
|||||||
"-o",
|
"-o",
|
||||||
"message-format=html",
|
"message-format=html",
|
||||||
"-o",
|
"-o",
|
||||||
"X-Mailer=CagettePei",
|
"message-header=X-Mailer: CagettePei",
|
||||||
"-f",
|
"-f",
|
||||||
fromString(e.getSender().name, e.getSender().email),
|
sugoi.mail.Mail.fromString(e.getSender().name, e.getSender().email),
|
||||||
"-t",
|
"-t",
|
||||||
to,
|
to,
|
||||||
"-bcc",
|
"-bcc",
|
||||||
bcc,
|
bcc,
|
||||||
"-u",
|
"-u",
|
||||||
e.getSubject(),
|
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)
|
// if (App.config.DEBUG)
|
||||||
// App.log('args=${args.join(" ")}');
|
// App.log('args=${args.join(" ")}');
|
||||||
|
|
||||||
var exitCode = Sys.command("sendemail", args);
|
var exitCode = Sys.command("sendemail", args);
|
||||||
// var exitCode = 0;
|
// 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)
|
if (exitCode == 0)
|
||||||
App.log('$summary successfully sent');
|
App.log('$summary successfully sent');
|
||||||
else
|
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