Skip to content

Instantly share code, notes, and snippets.

@dam1
Last active May 27, 2019 08:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dam1/209e5ed7e8e9fcad0a46157a1c724735 to your computer and use it in GitHub Desktop.
Save dam1/209e5ed7e8e9fcad0a46157a1c724735 to your computer and use it in GitHub Desktop.
Create an email with multiple attachment with resumable upload with Google Gmail Api
var fs = require('fs');
var request = require('request');
var EventEmitter = require('events').EventEmitter;
var mime = require('mime');
var util = require('util');
function gmailResumableUpload() {
this.byteCount = 0; //init variables
this.tokens = {};
this.filepath = '';
this.metadata = {};
this.query = '';
this.userId = '';
this.retry = -1;
this.host = 'www.googleapis.com';
this.api = '/upload/gmail/v1/users/';
this.api2 = '/drafts';
};
util.inherits(gmailResumableUpload, EventEmitter);
//Init the upload by POSTing google for an upload URL (saved to self.location)
gmailResumableUpload.prototype.upload = function () {
var self = this;
var options = {
url: 'https://' + self.host + self.api + self.userId + self.api2 + '?uploadType=resumable' + self.query,
headers: {
'Host': self.host,
'Authorization': 'Bearer ' + self.tokens.access_token,
'Content-Length': 0,
'X-Upload-Content-Length': fs.statSync(self.filepath).size,
'X-Upload-Content-Type': 'message/rfc822'
},
body: JSON.stringify(self.metadata)
};
//Send request and start upload if success
request.post(options, function (err, res, body) {
if (err || !res.headers.location) {
self.emit('error', new Error(err));
self.emit('progress', 'Retrying ...');
if ((self.retry > 0) || (self.retry <= -1)) {
self.retry--;
self.upload(); // retry
} else {
return;
}
}
self.location = res.headers.location;
self.send();
});
}
//Pipes uploadPipe to self.location (Google's Location header)
gmailResumableUpload.prototype.send = function () {
var self = this;
var options = {
url: self.location, //self.location becomes the Google-provided URL to PUT to
headers: {
'Authorization': 'Bearer ' + self.tokens.access_token,
'Content-Length': fs.statSync(self.filepath).size - self.byteCount,
'Content-Type': 'message/rfc822'
}
};
try {
//creates file stream, pipes it to self.location
var uploadPipe = fs.createReadStream(self.filepath, {
start: self.byteCount,
end: fs.statSync(self.filepath).size
});
} catch (e) {
self.emit('error', new Error(e));
return;
}
var health = setInterval(function () {
self.getProgress(function (err, res, body) {
if (!err && typeof res.headers.range !== 'undefined') {
self.emit('progress', res.headers.range.substring(8));
}
});
}, 5000);
uploadPipe.pipe(request.put(options, function (error, response, body) {
clearInterval(health);
if (!error) {
self.emit('success', body);
return;
}
self.emit('error', new Error(error));
if ((self.retry > 0) || (self.retry <= -1)) {
self.retry--;
self.getProgress(function (err, res, b) {
if (typeof res.headers.range !== 'undefined') {
self.byteCount = res.headers.range.substring(8); //parse response
} else {
self.byteCount = 0;
}
self.send();
});
}
}));
}
gmailResumableUpload.prototype.getProgress = function (handler) {
var self = this;
var options = {
url: self.location,
headers: {
'Authorization': 'Bearer ' + self.tokens.access_token,
'Content-Length': 0,
'Content-Range': 'bytes */' + fs.statSync(self.filepath).size
}
};
request.put(options, handler);
}
module.exports = gmailResumableUpload;
var GmailResumableUpload = require('./GmailResumableUpload');
exports.createDraftWithClient = function (client, emailFileMailPath, cb) {
var gmailResumableUpload = new GmailResumableUpload();
gmailResumableUpload.tokens = client.credentials; //Google OAuth2 tokens
gmailResumableUpload.userId = client.userId; // the gmail email
gmailResumableUpload.filepath = emailFileMailPath; // file path of the email, since it's a large email containing attachment you should safe it as a file
gmailResumableUpload.metadata = null;
// some optional parameters
gmailResumableUpload.query = '&supportsTeamDrives=true&';
gmailResumableUpload.retry = 3;
gmailResumableUpload.upload();
gmailResumableUpload.on('success', function (success) {
cb(null, JSON.parse(success))
});
gmailResumableUpload.on('error', function (error) {
cb(error);
});
};
@dam1
Copy link
Author

dam1 commented Mar 8, 2018

Use Nodemailer to compose the email with the attachments, save the result to a file, then upload it with this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment