@@ -19,21 +19,120 @@ function SendGridTransport(options) {
1919SendGridTransport . prototype . send = function ( mail , callback ) {
2020 var email = mail . data ;
2121
22- if ( typeof ( email . to ) === 'string' ) {
23- email . to = mail . data . to . split ( / [ , ] + / ) ;
22+ // fetch envelope data from the message object
23+ var addresses = mail . message . getAddresses ( ) ;
24+ var from = [ ] . concat ( addresses . from || addresses . sender || addresses [ 'reply-to' ] || [ ] ) . shift ( ) ;
25+ var to = [ ] . concat ( addresses . to || [ ] ) . concat ( addresses . cc || [ ] ) . concat ( addresses . bcc || [ ] ) ;
26+
27+ // populate from and fromname
28+ if ( from ) {
29+ if ( from . address ) {
30+ email . from = from . address ;
31+ }
32+
33+ if ( from . name ) {
34+ email . fromname = from . name ;
35+ }
2436 }
2537
26- if ( email . attachments ) {
27- email . files = email . attachments ;
38+ // populate to and toname arrays
39+ email . to = to . map ( function ( rcpt ) {
40+ return rcpt . address || '' ;
41+ } ) ;
42+
43+ email . toname = to . map ( function ( rcpt ) {
44+ return rcpt . name || '' ;
45+ } ) ;
46+
47+ // a list for processing attachments
48+ var contents = [ ] ;
49+
50+ // email.text could be a stream or a file, so store it for processing
51+ if ( email . text ) {
52+ contents . push ( {
53+ obj : email ,
54+ key : 'text'
55+ } ) ;
2856 }
2957
30- var fromSplit = email . from . match ( / ( .* ) \< ( .* ) \> / )
31- if ( fromSplit ) {
32- email . fromname = fromSplit [ 1 ] . trim ( ) ;
33- email . from = fromSplit [ 2 ] ;
58+ // email.html could be a stream or a file, so store it for processing
59+ if ( email . html ) {
60+ contents . push ( {
61+ obj : email ,
62+ key : 'html'
63+ } ) ;
3464 }
3565
36- this . sendgrid . send ( email , function ( err , json ) {
37- callback ( err , json ) ;
66+ // store attachments for processing, to fetch files, urls and streams
67+ email . files = email . attachments ;
68+ [ ] . concat ( email . files || [ ] ) . forEach ( function ( attachment , i ) {
69+ contents . push ( {
70+ obj : email . files ,
71+ key : i ,
72+ isAttachment : true
73+ } ) ;
3874 } ) ;
39- } ;
75+
76+ // fetch values for text/html/attachments as strings or buffers
77+ // this is an asynchronous action, so we'll handle it with a simple recursion
78+ var _self = this ;
79+ var pos = 0 ;
80+ var resolveContent = function ( ) {
81+
82+ // if all parts are processed, send out the e-mail
83+ if ( pos >= contents . length ) {
84+ return _self . sendgrid . send ( email , function ( err , json ) {
85+ callback ( err , json ) ;
86+ } ) ;
87+ }
88+
89+ // get the next element from the processing list
90+ var file = contents [ pos ++ ] ;
91+ /*
92+ We need to store a pointer to the original attachment object in case
93+ resolveContent replaces it with the Stream value
94+ */
95+ var prevObj = file . obj [ file . key ] ;
96+ // ensure the object is an actual attachment object, not a string, buffer or a stream
97+ if ( prevObj instanceof Buffer || typeof prevObj === 'string' || ( prevObj && typeof prevObj . pipe === 'function' ) ) {
98+ prevObj = {
99+ content : prevObj
100+ } ;
101+ }
102+
103+ // use the helper function to convert file paths, urls and streams to strings or buffers
104+ mail . resolveContent ( file . obj , file . key , function ( err , content ) {
105+ if ( err ) {
106+ return callback ( err ) ;
107+ }
108+
109+ if ( ! file . isAttachment ) {
110+ // overwrites email.text and email.html content
111+ file . obj [ file . key ] = content ;
112+ } else {
113+
114+ // If the object is a String or a Buffer then it is most likely replaces by resolveContent
115+ if ( file . obj [ file . key ] instanceof Buffer || typeof file . obj [ file . key ] === 'string' ) {
116+ file . obj [ file . key ] = prevObj ;
117+ }
118+ file . obj [ file . key ] . content = content ;
119+ if ( file . obj [ file . key ] . path ) {
120+ if ( ! file . obj [ file . key ] . filename ) {
121+ // try to detect the required filename from the path
122+ file . obj [ file . key ] . filename = file . obj [ file . key ] . path . split ( / [ \\ \/ ] / ) . pop ( ) ;
123+ }
124+ delete file . obj [ file . key ] . path ;
125+ }
126+ // set default filename if filename and content-type are not set (allowed for Nodemailer but not for SendGrid)
127+ if ( ! file . obj [ file . key ] . filename && ! file . obj [ file . key ] . contentType ) {
128+ file . obj [ file . key ] . filename = 'attachment-' + pos + '.bin' ;
129+ }
130+ }
131+
132+ resolveContent ( ) ;
133+ } ) ;
134+ } ;
135+
136+ // start the recursive function
137+ resolveContent ( ) ;
138+ } ;
0 commit comments