node simple-imap | list the subjects from simple-imap messages | send email | Search

This code downloads email attachments, saves them to a local directory, and generates HTML and Markdown previews for display.

Run example

npm run import -- "get attachments using simple-imap"

get attachments using simple-imap

var output = path.join(process.cwd(), 'output');
// TODO: convert the attachments to a virtual filesystem, lay it on top of the current app, run end-to-end tests
if (!fs.existsSync(output)) {
    fs.mkdirSync(output);
}

function getAttachments(messages) {
    attachments = []
    return Promise.all(messages.map(message => {
        return Promise.all(imaps.getParts(message.attributes.struct)
            .filter((part) => part.disposition && part.disposition.type === 'ATTACHMENT')
            // retrieve the attachments only of the messages with attachments 
            .map((part) => connection.getPartData(message, part).then((partData) => ({
                filename: part.disposition.params.filename,
                data: partData
            }))))
            .then(a => attachments = attachments.concat(a));
    }));
}

function saveAttachments(attachments) {
    var result = attachments.map((attachment) => {
        return new Promise((resolve, reject) => fs.writeFile(
            path.join(output, attachment.filename),
            attachment.data,
            'binary',
            function (err) {
                if (err) reject(err);
                else resolve(attachment);
            }));
    });
    return Promise.all(result).then(images => {
        html = '';
        htmlPrint = '';
        images.forEach((i) => {
            var filename = i.filename.split('/').pop();
            var ext = mime.lookup(i.filename);
            html += '<img src="data:' + ext + ';base64,' + (new Buffer(i.data, 'binary')).toString('base64') + '" />';
            htmlPrint += '<li><img src="/assets/' + filename + '" /></li>\n';
        });
        $.mime({'text/markdown': 'Usage:\n\n```html\n' + htmlPrint + '\n```\nOutput:\n' + html});
    })
}


What the code could have been:

const fs = require('fs');
const path = require('path');
const imaps = require('imap-simple');
const mime = require('mime-types');
const $ = require('jquery'); // assuming you are using a templating engine like EJS
const connection = imaps.connect({
  imap: {
    user: 'your-username',
    password: 'your-password',
    host: 'your-imap-host',
    port: 993,
    authTimeout: 10000,
    tls: true
  }
});

const OUTPUT_DIR = path.join(process.cwd(), 'output');

// Create output directory if it doesn't exist
if (!fs.existsSync(OUTPUT_DIR)) {
  fs.mkdirSync(OUTPUT_DIR);
}

/**
 * Retrieves attachments from a list of messages.
 *
 * @param {array} messages - List of messages to retrieve attachments from.
 * @returns {Promise} A promise that resolves to a list of attachments.
 */
function getAttachments(messages) {
  const attachments = [];

  return Promise.all(messages.map(async (message) => {
    const parts = await connection.getParts(message.attributes.struct);
    const attachmentParts = parts.filter((part) => part.disposition && part.disposition.type === 'ATTACHMENT');

    const attachmentData = await Promise.all(attachmentParts.map((part) => {
      return connection.getPartData(message, part).then((partData) => ({
        filename: part.disposition.params.filename,
        data: partData
      }));
    }));

    attachments.push(...attachmentData);
  }));
}

/**
 * Saves attachments to disk and generates HTML for displaying the images.
 *
 * @param {array} attachments - List of attachments to save.
 * @returns {Promise} A promise that resolves to the generated HTML.
 */
function saveAttachments(attachments) {
  const promises = attachments.map((attachment) => {
    const filename = path.join(OUTPUT_DIR, attachment.filename);
    return new Promise((resolve, reject) => {
      fs.writeFile(filename, attachment.data, 'binary', (err) => {
        if (err) reject(err);
        else resolve(attachment);
      });
    });
  });

  return Promise.all(promises).then((images) => {
    const html = images.map((image) => {
      const filename = image.filename.split('/').pop();
      const ext = mime.lookup(filename);
      return ``;
    }).join('');

    const htmlPrint = images.map((image) => {
      const filename = image.filename.split('/').pop();
      return `
  • `; }).join('\n'); return $.mime({ 'text/markdown': `Usage:\n\n```html\n${htmlPrint}\n```\nOutput:\n${html}` }); }); } // Example usage: getAttachments([/* list of messages */]) .then(saveAttachments) .then((html) => console.log(html));

    This code snippet downloads attachments from a set of emails and saves them to a local directory. It then generates HTML and Markdown representations of the attachments for display.

    Here's a breakdown:

    1. Setup: It defines an output directory (output) and creates it if it doesn't exist.

    2. Attachment Retrieval: The getAttachments function iterates through a list of emails (messages), extracts attachments from each email using imaps.getParts and connection.getPartData, and stores them in an array.

    3. Attachment Saving: The saveAttachments function takes the array of attachments and saves each attachment to the output directory using fs.writeFile.

    4. HTML and Markdown Generation: After saving the attachments, it generates HTML and Markdown code to display the attachments. The HTML code embeds the attachments as images using base64 encoding, while the Markdown code creates a list of image links.

    5. Output: Finally, it uses $.mime to send the generated HTML and Markdown code as a response.

    Essentially, this code automates the process of downloading email attachments, saving them locally, and generating HTML and Markdown representations for display.