• This repository has been archived on 02/Jun/2021
  • Stars
    star
    243
  • Rank 166,489 (Top 4 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 9 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Wrapper over node-imap, providing a simpler api for common use cases

imap-simple

This library is no longer maintained and has been archived.

A library providing a simpler interface for common use cases of node-imap, a robust imap client for node.js.

Warning: This library is missing a great deal of functionality from node-imap. If you have functionality you would like to see, we're accepting pull requests!

Examples

Retrieve the subject lines of all unread email

var imaps = require('imap-simple');

var config = {
    imap: {
        user: '[email protected]',
        password: 'yourpassword',
        host: 'imap.gmail.com',
        port: 993,
        tls: true,
        authTimeout: 3000
    }
};

imaps.connect(config).then(function (connection) {

    return connection.openBox('INBOX').then(function () {
        var searchCriteria = [
            'UNSEEN'
        ];

        var fetchOptions = {
            bodies: ['HEADER', 'TEXT'],
            markSeen: false
        };

        return connection.search(searchCriteria, fetchOptions).then(function (results) {
            var subjects = results.map(function (res) {
                return res.parts.filter(function (part) {
                    return part.which === 'HEADER';
                })[0].body.subject[0];
            });

            console.log(subjects);
            // =>
            //   [ 'Hey Chad, long time no see!',
            //     'Your amazon.com monthly statement',
            //     'Hacker Newsletter Issue #445' ]
        });
    });
});

Retrieve Body Content

var imaps = require('imap-simple');
const _ = require('lodash');

var config = {
    imap: {
        user: '[email protected]',
        password: 'yourpassword',
        host: 'imap.gmail.com',
        port: 993,
        tls: true,
        authTimeout: 3000
    }
};

imaps.connect(config).then(function (connection) {
    return connection.openBox('INBOX').then(function () {
        var searchCriteria = ['1:5'];
        var fetchOptions = {
            bodies: ['HEADER', 'TEXT'],
        };
        return connection.search(searchCriteria, fetchOptions).then(function (messages) {
            messages.forEach(function (item) {
                var all = _.find(item.parts, { "which": "TEXT" })
                var html = (Buffer.from(all.body, 'base64').toString('ascii'));
                console.log(html)
            });
        });
    });
});

Usage of Mailparser in combination with imap-simple

var imaps = require('imap-simple');
const simpleParser = require('mailparser').simpleParser;
const _ = require('lodash');

var config = {
    imap: {
        user: '[email protected]',
        password: 'yourpassword',
        host: 'imap.gmail.com',
        port: 993,
        tls: true,
        authTimeout: 3000
    }
};

imaps.connect(config).then(function (connection) {
    return connection.openBox('INBOX').then(function () {
        var searchCriteria = ['1:5'];
        var fetchOptions = {
            bodies: ['HEADER', 'TEXT', ''],
        };
        return connection.search(searchCriteria, fetchOptions).then(function (messages) {
            messages.forEach(function (item) {
                var all = _.find(item.parts, { "which": "" })
                var id = item.attributes.uid;
                var idHeader = "Imap-Id: "+id+"\r\n";
                simpleParser(idHeader+all.body, (err, mail) => {
                    // access to the whole mail object
                    console.log(mail.subject)
                    console.log(mail.html)
                });
            });
        });
    });
});

Download all attachments from all unread email since yesterday

var imaps = require('imap-simple');

var config = {
    imap: {
        user: '[email protected]',
        password: 'yourpassword',
        host: 'imap.gmail.com',
        port: 993,
        tls: true,
        authTimeout: 3000
    }
};

imaps.connect(config).then(function (connection) {

    connection.openBox('INBOX').then(function () {

        // Fetch emails from the last 24h
        var delay = 24 * 3600 * 1000;
        var yesterday = new Date();
        yesterday.setTime(Date.now() - delay);
        yesterday = yesterday.toISOString();
        var searchCriteria = ['UNSEEN', ['SINCE', yesterday]];
        var fetchOptions = { bodies: ['HEADER.FIELDS (FROM TO SUBJECT DATE)'], struct: true };

        // retrieve only the headers of the messages
        return connection.search(searchCriteria, fetchOptions);
    }).then(function (messages) {

        var attachments = [];

        messages.forEach(function (message) {
            var parts = imaps.getParts(message.attributes.struct);
            attachments = attachments.concat(parts.filter(function (part) {
                return part.disposition && part.disposition.type.toUpperCase() === 'ATTACHMENT';
            }).map(function (part) {
                // retrieve the attachments only of the messages with attachments
                return connection.getPartData(message, part)
                    .then(function (partData) {
                        return {
                            filename: part.disposition.params.filename,
                            data: partData
                        };
                    });
            }));
        });

        return Promise.all(attachments);
    }).then(function (attachments) {
        console.log(attachments);
        // =>
        //    [ { filename: 'cats.jpg', data: Buffer() },
        //      { filename: 'pay-stub.pdf', data: Buffer() } ]
    });
});

Append a message to your drafts folder

var imaps = require('imap-simple');

var config = {
    imap: {
        user: '[email protected]',
        password: 'yourpassword',
        host: 'imap.gmail.com',
        port: 993,
        tls: true,
        authTimeout: 3000
    }
};

imaps.connect(config).then(function (connection) {
  const message = `Content-Type: text/plain
To: [email protected]
Subject: Hello world

Hi
This is a test message
`;
  connection.append(message.toString(), {mailbox: 'Drafts', flags: '\\Draft'});
});

Open messages and delete them

imaps.connect(config).then(function (connection) {
    connection.openBox('INBOX').then(function () {

        var searchCriteria = ['ALL'];
        var fetchOptions = { bodies: ['TEXT'], struct: true };
        return connection.search(searchCriteria, fetchOptions);

    //Loop over each message
    }).then(function (messages) {
        let taskList = messages.map(function (message) {
            return new Promise((res, rej) => {
                var parts = imaps.getParts(message.attributes.struct);
                parts.map(function (part) {
                    return connection.getPartData(message, part)
                    .then(function (partData) {

                        //Display e-mail body
                        if (part.disposition == null && part.encoding != "base64"){
                            console.log(partData);
                        }

                        //Mark message for deletion
                        connection.addFlags(message.attributes.uid, "\Deleted", (err) => {
                            if (err){
                                console.log('Problem marking message for deletion');
                                rej(err);
                            }

                            res(); //Final resolve
                        })
                    });
                });
            });
        })

        return Promise.all(taskList).then(() => {
            connection.imap.closeBox(true, (err) => { //Pass in false to avoid delete-flagged messages being removed
                if (err){
                    console.log(err);
                }
            });
            connection.end();
        });
    });
});

delete messages by uid

imaps.connect(config).then(connection => {

    return connection.openBox('INBOX')
        .then(() => connection.search(['ALL'], {bodies: ['HEADER']}))
        .then( messages => {

            // select messages from bob
            const uidsToDelete = messages
                .filter( message => {
                    return message.parts
                    .filter( part => part.which === 'HEADER')[0].body.to[0] === '[email protected]';
                })
                .map(message => message.attributes.uid);

            return connection.deleteMessage(uidsToDelete);
        });
});

API

Exported module

  • connect(<object> options, [<function> callback]) - Promise - Main entry point. Connect to an Imap server. Upon successfully connecting to the Imap server, either calls the provided callback with signature (err, connection), or resolves the returned promise with connection, where connection is an instance of ImapSimple. If the connection times out, either the callback will be called with the err property set to an instance of ConnectionTimeoutError, or the returned promise will be rejected with the same. Valid options properties are:

    • imap: Options to pass to node-imap constructor 1:1
    • connectTimeout: Time in milliseconds to wait before giving up on a connection attempt. (Deprecated: please use options.imap.authTimeout instead)
  • errors.ConnectionTimeoutError(<number> timeout) - ConnectionTimeoutError - Error thrown when a connection attempt has timed out.

  • getParts(<Array> struct) - Array - Given the message.attributes.struct, retrieve a flattened array of parts objects that describe the structure of the different parts of the message's body. Useful for getting a simple list to iterate for the purposes of, for example, finding all attachments.

  • ImapSimple(<object> imap) - ImapSimple - constructor for creating an instance of ImapSimple. Mostly used for testing.

ImapSimple class

  • addFlags(<mixed> uid, <string> flag, [<function> callback]) - Promise - Adds the provided flag(s) to the specified message(s). uid is the uid of the message you want to add the flag to or an array of uids. flag is either a string or array of strings indicating the flags to add. When completed, either calls the provided callback with signature (err), or resolves the returned promise.

  • addMessageLabel(<mixed> source, <mixed> label, [<function> callback]) - Promise - Adds the provided label(s) to the specified message(s). source corresponds to a node-imap MessageSource which specifies the messages to be moved. label is either a string or array of strings indicating the labels to add. When completed, either calls the provided callback with signature (err), or resolves the returned promise.

  • removeMessageLabel(<mixed> source, <mixed> label, [<function> callback]) - Promise - Removes the provided label(s) from the specified message(s). source corresponds to a node-imap MessageSource which specifies the messages to be removed. label is either a string or array of strings indicating the labels to remove. When completed, either calls the provided callback with signature (err), or resolves the returned promise.

  • append(<mixed> message, [<object> options], [<function> callback]) - Promise - Appends the argument message to the currently open mailbox or another mailbox. message is a RFC-822 compatible MIME message. Valid options are mailbox, flags and date. When completed, either calls the provided callback with signature (err), or resolves the returned promise.

  • delFlags(<mixed> uid, <string> flag, [<function> callback]) - Promise - Removes the provided flag(s) from the specified message(s). uid is the uid of the message you want to remove the flag from or an array of uids. flag is either a string or array of strings indicating the flags to remove. When completed, either calls the provided callback with signature (err), or resolves the returned promise.

  • end() - undefined - Close the connection to the imap server.

  • getBoxes([<function> callback]) - Promise - Returns the full list of mailboxes (folders). Upon success, either the provided callback will be called with signature (err, boxes), or the returned promise will be resolved with boxes. boxes is the exact object returned from the node-imap getBoxes() result.

  • getPartData(<object> message, <object> part, [<function> callback]) - Promise - Downloads part data (which is either part of the message body, or an attachment). Upon success, either the provided callback will be called with signature (err, data), or the returned promise will be resolved with data. The data will be automatically decoded based on its encoding. If the encoding of the part is not supported, an error will occur.

  • deleteMessage(<mixed> uid, [<function> callback]) - Promise - Deletes the specified message(s). uid is the uid of the message you want to add the flag to or an array of uids. When completed, either calls the provided callback with signature (err), or resolves the returned promise.

  • moveMessage(<mixed> source, <string> boxName, [<function> callback]) - Promise - Moves the specified message(s) in the currently open mailbox to another mailbox. source corresponds to a node-imap MessageSource which specifies the messages to be moved. When completed, either calls the provided callback with signature (err), or resolves the returned promise.

  • openBox(<string> boxName, [<function> callback]) - Promise - Open a mailbox, calling the provided callback with signature (err, boxName), or resolves the returned promise with boxName.

  • closeBox(<boolean> [autoExpunge = true], [<function> callback]) - Promise - Close a mailbox, calling the provided callback with signature (err), or resolves the returned promise. If autoExpunge is true, any messages marked as Deleted in the currently open mailbox will be removed.

  • addBox(<string> boxName, [<function> callback]) - Promise - Create a mailbox, calling the provided callback with signature (err, boxName), or resolves the returned promise with boxName.

  • delBox(<string> boxName, [<function> callback]) - Promise - Delete a mailbox, calling the provided callback with signature (err, boxName), or resolves the returned promise with boxName.

  • search(<object> searchCriteria, [<object> fetchOptions], [<function> callback]) - Promise - Search for and retrieve mail in the currently open mailbox. The search is performed based on the provided searchCriteria, which is the exact same format as node-imap requires. All results will be subsequently downloaded, according to the options provided by fetchOptions, which are also identical to those passed to fetch of node-imap. Upon a successful search+fetch operation, either the provided callback will be called with signature (err, results), or the returned promise will be resolved with results. The format of results is detailed below. See node-imap's ImapMessage signature for information about attributes, which, size, and body. For any message part that is a HEADER, the body is automatically parsed into an object.

        // [{
        //      attributes: object,
        //      parts: [ { which: string, size: number, body: string }, ... ]
        //  }, ...]

Server events

Functions to listen to server events are configured in the configuration object that is passed to the connect function. ImapSimple only implements a subset of the server event functions that node-imap supports, see here, which are mail, expunge and update. Add them to the configuration object as follows:

var config = {
    imap: {
        ...
    },
    onmail: function (numNewMail) {
      ...
    },
    onexpunge: function (seqno) {
        ...
    },
    onupdate: function (seqno, info) {
        ...
    }
};

For more information see here.

Contributing

Pull requests welcome! This project really needs tests, so those would be very welcome. If you have a use case you want supported, please feel free to add, but be sure to follow the patterns established thus far, mostly:

  • support promises AND callbacks
  • make your api as simple as possible
  • don't worry about exposing implementation details of node-imap when needed

This project is OPEN open source. See CONTRIBUTING.md for more details about contributing.

Semver

This project follows semver. Namely:

  • new MAJOR versions when incompatible API changes are made,
  • new MINOR versions for backwards-compatible feature additions,
  • new PATCH versions for backwards-compatible bug fixes

License

MIT

More Repositories

1

awry

An Asterisk REST Interface (ARI) websocket and API client library
JavaScript
21
star
2

asterisk-playground

A sandbox to tinker with Asterisk and its many interfaces
JavaScript
8
star
3

my-api

a personal proxy api for various 3rd-party api services across the web
JavaScript
4
star
4

advent-of-code-2021

Because I don't have enough to do as it is.
Scala
3
star
5

microsoft-365-group-calendars-for-slack

Microsoft 365 Group Calendar Integration for Slack
JavaScript
2
star
6

tfpeek

Go
2
star
7

gophercises

Go
2
star
8

scala-reactive-course-edx

Going through the "Programming Reactive Systems" course on EdX
Scala
2
star
9

chadmcelligott.com

my (old) personal website that uses Jekyll static site generator
CSS
2
star
10

go-by-example

Go
2
star
11

waterline-custom-validations

a library to help build validation messages that mimic the structure of waterline 0.10 validation messages
JavaScript
2
star
12

advent-of-code-2022

Ho Ho Ho! Merry Christmas!
Rust
2
star
13

yap_website

Yet another personal website for fiddling
Python
1
star
14

chadxz.github.io

personal website. http://chadmcelligott.com
HTML
1
star
15

ssh-ec2

Project from @danjenkins to ssh into ec2 instances
JavaScript
1
star
16

respoke-brokered-auth-boilerplate

Barebones boilerplate for brokered auth with Respoke
JavaScript
1
star
17

vanilla-webrtc

Toy project to experiment with plain webrtc apis
JavaScript
1
star
18

kubernetes-the-hard-way-aws

Learning stuff.
HCL
1
star
19

personal-website

The source of my personal website at https://chadxz.dev
Nunjucks
1
star
20

s3-delete-objects-action

A Github Action to remove objects from a versioned or unversioned AWS S3 bucket.
JavaScript
1
star
21

hwclring

a hello world ring application
Clojure
1
star
22

fbaas-rust

Fizz Buzz, as a service, in Rust
Rust
1
star
23

katacoda-scenarios

Katacoda Scenarios
1
star
24

respoke-app-express-boilerplate

Boilerplate for the server-side portion of a Respoke application
JavaScript
1
star
25

PixaMuzei

Muzei plugin using images from Pixabay
Kotlin
1
star
26

personal-site-angular

rewrite of personal site using angular 6
TypeScript
1
star
27

express-app-auth-boilerplate

Boilerplate for building a web application with authentication
JavaScript
1
star
28

github-profile-php

PHP example of rendering github profile data
PHP
1
star
29

tragic

An Asterisk Gateway Interface client library
C
1
star
30

personal-site-react

rewrite of personal site using react + webpack
JavaScript
1
star
31

personal-site-rewrite

rewriting some of the dynamic functionality of chadmcelligott.com using backbone.js and require.js
JavaScript
1
star
32

generator-dotfiles

Yeoman generator for my dotfiles
JavaScript
1
star
33

hellogqlgen

hellogqlgen
Starlark
1
star
34

.vim

my vim dotfiles
Vim Script
1
star
35

RESTful-web-service

teaching myself the ins and outs of RESTful web services, server-side javascript and TDD
JavaScript
1
star
36

exercism

My solutions for completed exercism exercises
Clojure
1
star
37

waterline-fakes

Utilities to make it easier to fake out waterline models and collections for unit testing
JavaScript
1
star
38

trpc-express-demo

TypeScript
1
star