mirror of
https://github.com/eleith/emailjs.git
synced 2024-07-05 20:10:37 +00:00
move address parsing to a maintained module
This commit is contained in:
parent
aba99c406e
commit
3a89b55392
57
package.json
57
package.json
@ -1,36 +1,39 @@
|
||||
{
|
||||
"name": "emailjs",
|
||||
"description": "send text/html emails and attachments (files, streams and strings) from node.js to any smtp server",
|
||||
"version": "0.3.14",
|
||||
"author": "eleith",
|
||||
"contributors":["izuzak", "Hiverness", "mscdex", "jimmybergman"],
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "http://github.com/eleith/emailjs.git"
|
||||
},
|
||||
"dependencies":
|
||||
{
|
||||
"moment" : "= 1.7.0",
|
||||
"name": "emailjs",
|
||||
"description": "send text/html emails and attachments (files, streams and strings) from node.js to any smtp server",
|
||||
"version": "0.3.15",
|
||||
"author": "eleith",
|
||||
"contributors": [
|
||||
"izuzak",
|
||||
"Hiverness",
|
||||
"mscdex",
|
||||
"jimmybergman"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/eleith/emailjs.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"addressparser": "^0.3.2",
|
||||
"mimelib": "0.2.14",
|
||||
"moment": "= 1.7.0",
|
||||
"starttls": "0.2.1"
|
||||
},
|
||||
"optionalDependencies":
|
||||
{
|
||||
"bufferjs": "=1.1.0"
|
||||
},
|
||||
"devDependencies":
|
||||
{
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bufferjs": "=1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "= 1.7.4",
|
||||
"chai": "= 1.1.0",
|
||||
"simplesmtp": "0.3.32",
|
||||
"mailparser": "0.4.1",
|
||||
"iconv": "2.1.6"
|
||||
},
|
||||
"engine": ["node >= 0.10"],
|
||||
"main": "email",
|
||||
"scripts":
|
||||
{
|
||||
"test": "mocha -R spec -t 5000"
|
||||
}
|
||||
},
|
||||
"engine": [
|
||||
"node >= 0.10"
|
||||
],
|
||||
"main": "email",
|
||||
"scripts": {
|
||||
"test": "mocha -R spec -t 5000"
|
||||
}
|
||||
}
|
||||
|
416
smtp/address.js
416
smtp/address.js
@ -1,416 +0,0 @@
|
||||
/*
|
||||
* Email address parsing code.
|
||||
* rewritten with python's (2.7) email/_parseaddr.py as the starting point
|
||||
*/
|
||||
|
||||
var SPACE = ' ';
|
||||
var EMPTYSTRING = '';
|
||||
var COMMASPACE = ', ';
|
||||
|
||||
var quote = function(str)
|
||||
{
|
||||
// Add quotes around a string.
|
||||
return str.replace(/\\\\/g, '\\\\').replace(/"/g, '\\"');
|
||||
};
|
||||
|
||||
/*
|
||||
* To understand what this class does, it helps to have a copy of RFC 2822 in
|
||||
* front of you.
|
||||
*/
|
||||
|
||||
var Address = function(field)
|
||||
{
|
||||
/*
|
||||
* Initialize a new instance.
|
||||
* `field' is an unparsed address header field, containing
|
||||
* one or more addresses.
|
||||
*/
|
||||
|
||||
this.specials = '()<>@,:;.\"[]';
|
||||
this.pos = 0;
|
||||
this.LWS = ' \t';
|
||||
this.CR = '\r\n';
|
||||
this.FWS = this.LWS + this.CR;
|
||||
this.atomends = this.specials + this.LWS + this.CR;
|
||||
|
||||
// Note that RFC 2822 now specifies `.' as obs-phrase, meaning that it
|
||||
// is obsolete syntax. RFC 2822 requires that we recognize obsolete
|
||||
// syntax, so allow dots in phrases.
|
||||
|
||||
this.phraseends = this.atomends.replace(/\./g, '');
|
||||
this.field = field || "";
|
||||
this.commentlist = [];
|
||||
};
|
||||
|
||||
Address.prototype =
|
||||
{
|
||||
gotonext: function()
|
||||
{
|
||||
//Parse up to the start of the next address.
|
||||
while(this.pos < this.field.length)
|
||||
{
|
||||
if((this.LWS + '\n\r').indexOf(this.field[this.pos]) != -1)
|
||||
this.pos++;
|
||||
|
||||
else if(this.field[this.pos] == '(')
|
||||
this.commentlist.push(this.getcomment());
|
||||
|
||||
else
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
getlist: function()
|
||||
{
|
||||
// Parse all addresses. Returns a list containing all of the addresses
|
||||
var result = [], ad;
|
||||
|
||||
while(this.pos < this.field.length)
|
||||
{
|
||||
ad = this.get();
|
||||
|
||||
if(ad)
|
||||
result.push(ad);
|
||||
|
||||
else
|
||||
result.push({label:'', address:''});
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
get: function()
|
||||
{
|
||||
// Parse the next address
|
||||
this.commentlist = [];
|
||||
this.gotonext();
|
||||
|
||||
var oldpos = this.pos, oldcl = this.commentlist, plist = this.getphraselist(), returnlist = [],
|
||||
addrspec, fieldlen, routeaddr;
|
||||
|
||||
this.gotonext();
|
||||
|
||||
if(this.pos >= this.field.length)
|
||||
{
|
||||
// Bad email address, no domain
|
||||
if(plist.length)
|
||||
returnlist = {label:this.commentlist.join(SPACE), address:plist[0]};
|
||||
}
|
||||
|
||||
else if('.@'.indexOf(this.field[this.pos]) != -1)
|
||||
{
|
||||
// email address is just an addrspec
|
||||
// this isn't very efficient since we start over
|
||||
this.pos = oldpos;
|
||||
this.commentlist = oldcl;
|
||||
addrspec = this.getspec();
|
||||
returnlist = {label:this.commentlist.join(SPACE), address:addrspec};
|
||||
}
|
||||
|
||||
else if(this.field[this.pos] == ':')
|
||||
{
|
||||
// address is a group
|
||||
returnlist = [];
|
||||
fieldlen = this.field.length;
|
||||
this.pos++;
|
||||
|
||||
while(this.pos < this.field.length)
|
||||
{
|
||||
this.gotonext();
|
||||
|
||||
if(this.pos < fieldlen && this.field[this.pos] == ';')
|
||||
{
|
||||
this.pos += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
returnlist = returnlist.push(this.get());
|
||||
}
|
||||
}
|
||||
|
||||
else if(this.field[this.pos] == '<')
|
||||
{
|
||||
// Address is a prhase then a route addr
|
||||
routeaddr = this.getroute();
|
||||
|
||||
if(this.commentlist.length)
|
||||
returnlist = {label:plist.join(SPACE) + ' (' + this.commentlist.join(SPACE) + ')', address:routeaddr};
|
||||
|
||||
else
|
||||
returnlist = {label:plist.join(SPACE), address:routeaddr};
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if(plist.length)
|
||||
returnlist = {label:this.commentlist.join(SPACE), address:plist[0]};
|
||||
|
||||
else if(this.specials.indexOf(this.field[this.pos]) != -1)
|
||||
this.pos++;
|
||||
}
|
||||
|
||||
this.gotonext();
|
||||
|
||||
if(this.pos < this.field.length && this.field[this.pos] == ',')
|
||||
this.pos++;
|
||||
|
||||
return returnlist;
|
||||
},
|
||||
|
||||
getroute: function()
|
||||
{
|
||||
// Parse a route address. this method skips all route stuff and returns addrspec
|
||||
if(this.field[this.pos] != '<')
|
||||
return '';
|
||||
|
||||
var expectroute = false, adlist = '';
|
||||
|
||||
this.pos++;
|
||||
this.gotonext();
|
||||
|
||||
while(this.pos < this.field.length)
|
||||
{
|
||||
if(expectroute)
|
||||
{
|
||||
this.getdomain();
|
||||
expectroute = false;
|
||||
}
|
||||
else if(this.field[this.pos] == '>')
|
||||
{
|
||||
this.pos += 1;
|
||||
break;
|
||||
}
|
||||
else if(this.field[this.pos] == '@')
|
||||
{
|
||||
this.pos += 1;
|
||||
expectroute = true;
|
||||
}
|
||||
else if(this.field[this.pos] == ':')
|
||||
{
|
||||
this.pos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
adlist = this.getspec();
|
||||
this.pos++;
|
||||
break;
|
||||
}
|
||||
|
||||
this.gotonext();
|
||||
}
|
||||
|
||||
return adlist;
|
||||
},
|
||||
|
||||
getspec: function()
|
||||
{
|
||||
//parse an RFC 2822 addr-spec
|
||||
var aslist = [];
|
||||
|
||||
this.gotonext();
|
||||
|
||||
while(this.pos < this.field.length)
|
||||
{
|
||||
if(this.field[this.pos] == '.')
|
||||
{
|
||||
aslist.push('.');
|
||||
this.pos++;
|
||||
}
|
||||
|
||||
else if(this.field[this.pos] == '"')
|
||||
aslist.push('"' + this.getquote() + '"');
|
||||
|
||||
else if(this.atomends.indexOf(this.field[this.pos]) != -1)
|
||||
break;
|
||||
|
||||
else
|
||||
aslist.push(this.getatom());
|
||||
|
||||
this.gotonext();
|
||||
}
|
||||
|
||||
if(this.pos >= this.field.length || this.field[this.pos] != '@')
|
||||
return aslist.join(EMPTYSTRING);
|
||||
|
||||
aslist.push('@');
|
||||
this.pos++;
|
||||
this.gotonext();
|
||||
|
||||
return aslist.join(EMPTYSTRING) + this.getdomain();
|
||||
},
|
||||
|
||||
getdomain: function()
|
||||
{
|
||||
// get the complete domain name from an address
|
||||
var sdlist = [];
|
||||
|
||||
while(this.pos < this.field.length)
|
||||
{
|
||||
if(this.LWS.indexOf(this.field[this.pos]) != -1)
|
||||
this.pos++;
|
||||
|
||||
else if(this.field[this.pos] == '(')
|
||||
this.commentlist.push(this.getcomment());
|
||||
|
||||
else if(this.field[this.pos] == '[')
|
||||
sdlist.push(this.getdomainliteral());
|
||||
|
||||
else if(this.field[this.pos] == '.')
|
||||
{
|
||||
this.pos++;
|
||||
sdlist.push('.');
|
||||
}
|
||||
|
||||
else if(this.atomends.indexOf(this.field[this.pos]) != -1)
|
||||
break;
|
||||
|
||||
else
|
||||
sdlist.push(this.getatom());
|
||||
}
|
||||
|
||||
return sdlist.join(EMPTYSTRING);
|
||||
},
|
||||
|
||||
getdelimited: function(beginchar, endchars, allowcomments)
|
||||
{
|
||||
/*
|
||||
* Parse a header fragment delimited by special characters.
|
||||
*
|
||||
* `beginchar' is the start character for the fragment.
|
||||
* If self is not looking at an instance of `beginchar' then
|
||||
* getdelimited returns the empty string.
|
||||
*
|
||||
* `endchars' is a sequence of allowable end-delimiting characters.
|
||||
* Parsing stops when one of these is encountered.
|
||||
*
|
||||
* If `allowcomments' is non-zero, embedded RFC 2822 comments are allowed
|
||||
* within the parsed fragment.
|
||||
*/
|
||||
|
||||
if(this.field[this.pos] != beginchar)
|
||||
return '';
|
||||
|
||||
allowcomments = (allowcomments === false) ? false : true;
|
||||
var slist = [''], quote = false;
|
||||
this.pos++;
|
||||
|
||||
while(this.pos < this.field.length)
|
||||
{
|
||||
if(quote)
|
||||
{
|
||||
slist.push(this.field[this.pos]);
|
||||
quote = false;
|
||||
}
|
||||
else if(endchars.indexOf(this.field[this.pos]) != -1)
|
||||
{
|
||||
this.pos++;
|
||||
break;
|
||||
}
|
||||
else if(allowcomments && this.field[this.pos] == '(')
|
||||
{
|
||||
slist.push(this.getcomment());
|
||||
continue;
|
||||
}
|
||||
|
||||
else if(this.field[this.pos] == '\\')
|
||||
quote = true;
|
||||
|
||||
else
|
||||
slist.push(this.field[this.pos]);
|
||||
|
||||
this.pos++;
|
||||
|
||||
}
|
||||
|
||||
return slist.join(EMPTYSTRING);
|
||||
},
|
||||
|
||||
getquote: function()
|
||||
{
|
||||
// get a quote-delimited fragment from self's field
|
||||
return this.getdelimited('"', '"\r', false);
|
||||
},
|
||||
|
||||
getcomment: function()
|
||||
{
|
||||
// Get a parenthesis-delimited fragment from self's field.
|
||||
return this.getdelimited('(', ')\r', true);
|
||||
},
|
||||
|
||||
getdomainliteral: function()
|
||||
{
|
||||
// parse an rfc 2822 domain literal
|
||||
return '[' + this.getdelimited('[', ']\r', false) + ']';
|
||||
},
|
||||
|
||||
getatom: function(atomends)
|
||||
{
|
||||
/*
|
||||
* Parse an RFC 2822 atom.
|
||||
*
|
||||
* Optional atomends specifies a different set of end token delimiters
|
||||
* (the default is to use this.atomends). This is used e.g. in
|
||||
* getphraselist() since phrase endings must not include the `.' (which
|
||||
* is legal in phrases).
|
||||
*/
|
||||
|
||||
var atomlist = [''];
|
||||
|
||||
if(atomends === undefined)
|
||||
atomends = this.atomends;
|
||||
|
||||
while(this.pos < this.field.length)
|
||||
{
|
||||
if(atomends.indexOf(this.field[this.pos]) != -1)
|
||||
break;
|
||||
|
||||
else
|
||||
atomlist.push(this.field[this.pos]);
|
||||
|
||||
this.pos++;
|
||||
}
|
||||
|
||||
return atomlist.join(EMPTYSTRING);
|
||||
},
|
||||
|
||||
getphraselist: function()
|
||||
{
|
||||
/*
|
||||
* Parse a sequence of RFC 2822 phrases.
|
||||
*
|
||||
* A phrase is a sequence of words, which are in turn either RFC 2822
|
||||
* atoms or quoted-strings. Phrases are canonicalized by squeezing all
|
||||
* runs of continuous whitespace into one space.
|
||||
*/
|
||||
|
||||
var plist = [];
|
||||
|
||||
while(this.pos < this.field.length)
|
||||
{
|
||||
if(this.FWS.indexOf(this.field[this.pos]) != -1)
|
||||
this.pos++;
|
||||
|
||||
else if(this.field[this.pos] == '"')
|
||||
plist.push(this.getquote());
|
||||
|
||||
else if(this.field[this.pos] == '(')
|
||||
this.commentlist.push(this.getcomment());
|
||||
|
||||
else if(this.phraseends.indexOf(this.field[this.pos]) != -1)
|
||||
break;
|
||||
|
||||
else
|
||||
plist.push(this.getatom(this.phraseends));
|
||||
}
|
||||
|
||||
return plist;
|
||||
}
|
||||
};
|
||||
|
||||
exports.Address = Address;
|
||||
exports.parse = function(field)
|
||||
{
|
||||
var addresses = (new Address(field)).getlist();
|
||||
|
||||
return addresses.length ? addresses : [];
|
||||
};
|
@ -1,7 +1,7 @@
|
||||
var smtp = require('./smtp');
|
||||
var smtpError = require('./error');
|
||||
var message = require('./message');
|
||||
var address = require('./address');
|
||||
var addressparser= require('addressparser');
|
||||
|
||||
var Client = function(server)
|
||||
{
|
||||
@ -97,19 +97,19 @@ Client.prototype =
|
||||
var stack =
|
||||
{
|
||||
message: msg,
|
||||
to: address.parse(msg.header.to),
|
||||
from: address.parse(msg.header.from)[0].address,
|
||||
to: addressparser(msg.header.to),
|
||||
from: addressparser(msg.header.from)[0].address,
|
||||
callback: callback || function() {}
|
||||
};
|
||||
|
||||
if(msg.header.cc)
|
||||
stack.to = stack.to.concat(address.parse(msg.header.cc));
|
||||
stack.to = stack.to.concat(addressparser(msg.header.cc));
|
||||
|
||||
if(msg.header.bcc)
|
||||
stack.to = stack.to.concat(address.parse(msg.header.bcc));
|
||||
stack.to = stack.to.concat(addressparser(msg.header.bcc));
|
||||
|
||||
if(msg.header['return-path'] && address.parse(msg.header['return-path']).length)
|
||||
stack.returnPath = address.parse(msg.header['return-path'])[0].address;
|
||||
if(msg.header['return-path'] && addressparser(msg.header['return-path']).length)
|
||||
stack.returnPath = addressparser(msg.header['return-path'])[0].address;
|
||||
|
||||
self.queue.push(stack);
|
||||
self._poll();
|
||||
|
@ -5,7 +5,7 @@ var os = require('os');
|
||||
var path = require('path');
|
||||
var moment = require('moment');
|
||||
var mimelib = require('mimelib');
|
||||
var address = require('./address');
|
||||
var addressparser = require('addressparser');
|
||||
var CRLF = "\r\n";
|
||||
var MIMECHUNK = 76; // MIME standard wants 76 char chunks when sending out.
|
||||
var BASE64CHUNK= 24; // BASE64 bits needed before padding is used
|
||||
@ -32,20 +32,10 @@ var generate_boundary = function()
|
||||
|
||||
function person2address(l)
|
||||
{
|
||||
// an array of emails or name+emails
|
||||
if (Array.isArray(l)) {
|
||||
l = l.join(', ');
|
||||
}
|
||||
|
||||
// a string of comma separated emails or comma separated name+<emails>
|
||||
if(typeof l == 'string') {
|
||||
var addresses = address.parse(l);
|
||||
return addresses.map(function(addr) {
|
||||
return addr.label !== '' ? mimelib.encodeMimeWord(addr.label, 'Q', 'utf-8') + ' ' + '<' + addr.address + '>' : addr.address;
|
||||
}).join(', ');
|
||||
}
|
||||
|
||||
return null;
|
||||
var addresses = addressparser(l);
|
||||
return addresses.map(function(addr) {
|
||||
return addr.name ? mimelib.encodeMimeWord(addr.name, 'Q', 'utf-8').replace(/,/g, '=2C') + ' ' + '<' + addr.address + '>' : addr.address;
|
||||
}).join(', ');
|
||||
}
|
||||
|
||||
var fix_header_name_case = function(header_name) {
|
||||
|
Loading…
Reference in New Issue
Block a user