'How do you download an attachment with Gmail API with nodejs?

Im trying to make a node app on my local computer that does this:

1) Looks at my gmail inbox.

2) If an email has a certain label and an attachment, download it.

Im on step 2.

The part Im confused about is the part about 'parts'.

https://developers.google.com/gmail/api/v1/reference/users/messages/attachments/get

Googles sample code:

function getAttachments(userId, message, callback) {
  var parts = message.payload.parts;
  for (var i = 0; i < parts.length; i++) {
    var part = parts[i];
    if (part.filename && part.filename.length > 0) {
      var attachId = part.body.attachmentId;
      var request = gapi.client.gmail.users.messages.attachments.get({
        'id': attachId,
        'messageId': message.id,
        'userId': userId
      });
      request.execute(function(attachment) { // <--- that attachment param
        callback(part.filename, part.mimeType, attachment);
      });
    }
  }
}

It seems that 'attachment' contains the attachment data.

Here is my code:

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

gmail.users.messages.list({
  userId: 'me',
  'q':'subject:my-test has:nouserlabels has:attachment'
}, (err, res) => {
  if (err) return console.log('1 The API returned an error: ' + err);

  const msgs = res.data.messages;

  if(typeof msgs !== 'undefined'){
    console.log('Messages:');
    msgs.forEach( msg => {

      console.log(`- ${msg.id}`);

      gmail.users.messages.get({
        userId: 'me',
        id: msg.id,
        format:'full'
      },(err, res) => {
        if (err) return console.log('2 The API returned an error: ' + err);

        // Wheres the data????? //

        console.log('A')
        console.log(res.data.payload.parts)

        console.log('B')
        console.log(res.data.payload.parts[1])

        console.log('C')
        console.log(res.data.payload.parts[1].body)
      })
    });
  } else {
    console.log('no messages found')
  }


});


Solution 1:[1]

I've just used this to retrieve the docs from my favorite accountant.

const fsPromises = require('fs/promises');
const path = require('path');
const {google} = require('googleapis');
const readline = require('readline');
const fs = require('fs');
 
.... code from https://developers.google.com/gmail/api/quickstart/nodejs for auth

const fromEmail = process.argv[2];
const shortFromEmail = fromEmail.substring(0, fromEmail.indexOf('@'));
/**
 * Lists the labels in the user's account.
 *
 * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
 */
async function main(auth) {
  const gmail = google.gmail({version: 'v1', auth})
//  console.log('list messages with attachments auth: ' + JSON.stringify(auth))
  const {data} = await gmail.users.messages.list({
    userId: 'me',
    'q':`from:${fromEmail} has:nouserlabels has:attachment`,
//    maxResults: 5
  });
  console.log(data);
  let {messages} = data;
  await messages.reduce(async function (accProm, messageId) {
    await accProm;
    const {data: message} = await gmail.users.messages.get({
      userId: 'me',
      id: messageId.id,
      format: 'full'
    });
//    console.log(JSON.stringify(message, null, 2));
    let messagePayloadParts = message.payload.parts 
    const attachments = await messagePayloadParts.reduce(async function (acc2Prom, part) {
      const acc2 = await acc2Prom;
      if (!part.body.size || part.body.attachmentId == undefined) {
        return acc2;
      }
      const internalDate = new Date(parseInt(message.internalDate, 10));
      const datestring = internalDate.getFullYear() + " " + (internalDate.getMonth()+1).toString().padStart(2, "0") + " " + internalDate.getDate().toString().padStart(2, "0");
      console.log(datestring, shortFromEmail, part.filename, part)
      let fileExt;
      switch (part.mimeType) {
      case 'application/octet-stream': fileExt = ''; break;
      case 'application/pdf': fileExt = 'pdf'; break;
      case 'message/rfc822': fileExt = 'eml'; break;
      case 'image/jpeg': fileExt = 'jpg'; break;
      case 'image/png': fileExt = 'png'; break;
      case 'application/msword': fileExt = 'doc'; break;
      default: console.error('unknownMimeType', part.mimeType); boom;
      }
      const dirname = `${datestring} ${shortFromEmail}`;
      const filename = part.filename ? part.filename : `noname_${part.body.attachmentId.substring(0,8)}.${fileExt}`
      const attachmentPath = path.join(dirname, filename);
      const s = await fsPromises.stat(attachmentPath).catch(e => undefined);
      if (s) { return acc2 };
      const {data: attachment} = await gmail.users.messages.attachments.get({
        userId: 'me',
        messageId: message.id,
        id: part.body.attachmentId,
      });
      const { size, data: dataB64 } = attachment;
      await fsPromises.mkdir(dirname, {recursive: true});
      await fsPromises.writeFile(attachmentPath, Buffer.from(dataB64, 'base64'));
      return acc2;
 //   console.log('callback: ' + JSON.stringify(attachments))
    }, Promise.resolve([]));
  }, Promise.resolve());
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 FredG