0

When mail is sent with multiple attachments using gmail api, mail is not going properly. Attachments are not going in mail, instead some code is going in mail. I am using node js and request-promise module for achieving this.

I have tried sending attachments by setting boundaries on attachments. Here is the piece of code that I have written.

let user = await db.model('User').findOne({ _id: userId });
    let from = user.crmOptions.email;
    let mailString = '';
    for (let i in req.files) {
      mailString += '--boundary_mail1\n' + ','
      mailString += `Content-Type: ${req.files[i].mimetype}\n` + ','
      mailString += `Content-Disposition: attachment; filename="${req.files[i].filename}"\n` + ','
      mailString += "Content-Transfer-Encoding: base64\n\n" + ','
      mailString += `${fs.readFileSync(req.files[i].path).toString('base64')}` + ',' + '\n'
      if (i !== req.files.length - 1)
      mailString += ','
    }    
    let raw = [
      'MIME-Version: 1.0\n',
      "to: ", req.body.to, "\n",
      "from: ", from, "\n",
      "cc: ", req.body.cc ? req.body.cc : '', "\n",
      "bcc: ", req.body.bcc ? req.body.bcc : '', "\n",
      "subject: ", req.body.subject ? req.body.subject : '', "\n",
      "Content-Type: multipart/mixed; boundary=boundary_mail1\n\n",

      "--boundary_mail1\n",
      "Content-Type: multipart/alternative; boundary=boundary_mail2\n\n",

      "--boundary_mail2\n",
      "Content-Type: text/html; charset=UTF-8\n",
      "Content-Transfer-Encoding: quoted-printable\n\n",
      req.body.message = req.body.message ? req.body.message : '', "\n\n",
      "--boundary_mail2--\n",
      mailString,
      '--boundary_mail1--',
    ].join('');
    const id = 'me';
    let options = {
      url: "https://www.googleapis.com/upload/gmail/v1/users/" + id + "/messages/send?uploadType=multipart",
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${user.crmOptions.access_token}`,
        'Content-Type': 'message/rfc822'
      },
      body: raw
    };

await request(options).then(async body => {
  console.log("Body: ", body);
}).catch(err => {
  console.log("Error: ", err);
})

I want email to be delivered with multiple attachments. But I am not able to send mail with single attachment also. Could anyone help me resolve the issue.

2 Answers2

2

I found out issue guys. Just removed unwanted commas and its working. here is the modified code.

let user = await db.model('User').findOne({ _id: userId });
    let from = user.crmOptions.email;
    let mailString = '';
    for (let i in req.files) {
      mailString += '--boundary_mail1\n'
      mailString += `Content-Type: ${req.files[i].mimetype}\n`
      mailString += `Content-Disposition: attachment; filename="${req.files[i].filename}"\n`
      mailString += "Content-Transfer-Encoding: base64\n\n"
      mailString += `${fs.readFileSync(req.files[i].path).toString('base64')}` + '\n'
    }
    let raw = [
      'MIME-Version: 1.0\n',
      "to: ", req.body.to, "\n",
      "from: ", from, "\n",
      "cc: ", req.body.cc ? req.body.cc : '', "\n",
      "bcc: ", req.body.bcc ? req.body.bcc : '', "\n",
      "subject: ", req.body.subject ? req.body.subject : '', "\n",
      "Content-Type: multipart/mixed; boundary=boundary_mail1\n\n",

      "--boundary_mail1\n",
      "Content-Type: multipart/alternative; boundary=boundary_mail2\n\n",

      "--boundary_mail2\n",
      "Content-Type: text/html; charset=UTF-8\n",
      "Content-Transfer-Encoding: quoted-printable\n\n",
      req.body.message = req.body.message ? req.body.message : '', "\n\n",
      "--boundary_mail2--\n",
      mailString,
      '--boundary_mail1--',
    ].join('');
    const id = 'me';
    let options = {
      url: "https://www.googleapis.com/upload/gmail/v1/users/" + id + "/messages/send?uploadType=multipart",
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${user.crmOptions.access_token}`,
        'Content-Type': 'message/rfc822'
      },
      body: raw
    };
await request(options).then(async body => {
  console.log("Body: ", body);
}).catch(err => {
  console.log("Error: ", err);
})
0

This solution is working in Nodejs install google API's library

const { google } = require('googleapis');

static async sendEmail(refresh_token, to, subject, message, files) {
    const oauth2Client = new google.auth.OAuth2(
                config.get('service:google:client_id'),
                config.get('service:google:client_secret'),
                `${config.get('hostname')}/webhook/google/oauth-redirect`
            );

            // get access_token
            oauth2Client.setCredentials({
                refresh_token
            });

            // init gmail api
            const gmail = google.gmail({
                version: 'v1',
                auth: oauth2Client
            });

            

            const raw = await this.makeBodyWithAttachments(to, subject, message, files);

            const res = await gmail.users.messages.send({
                userId: 'me',
                uploadType: 'multipart',
                requestBody: {
                    raw
                }
            });
}

static async makeBodyWithAttachments(to, subject, message, files) {

    let mailString = '';
    for (let i in files) {
        mailString += '--boundary_mail1\n'
        mailString += `Content-Type: ${files[i].mimetype}\n`
        mailString += `Content-Disposition: attachment; filename="${files[i].filename}"\n`
        mailString += "Content-Transfer-Encoding: base64\n\n"
        mailString += `${fs.readFileSync(files[i].path).toString('base64')}` + '\n'
    }

    let raw = [
    'MIME-Version: 1.0\n',
    "to: ", to, "\n",
    "subject: ", subject ? subject : '', "\n",
    "Content-Type: multipart/mixed; boundary=boundary_mail1\n\n",

    "--boundary_mail1\n",
    "Content-Type: multipart/alternative; boundary=boundary_mail2\n\n",

    "--boundary_mail2\n",
    "Content-Type: text/html; charset=UTF-8\n",
    "Content-Transfer-Encoding: quoted-printable\n\n",
    message = message ? message : '', "\n\n",
    "--boundary_mail2--\n",
    mailString,
    '--boundary_mail1--',
    ].join('');

    return Buffer(raw).toString("base64").replace(/\+/g, '-').replace(/\//g, '_');
}
Saad Ahmed
  • 700
  • 1
  • 8
  • 15