Manage Your're Mail Using IMAP
Tags: node, imap, email, javascript
Published: 2020-03-02 07:19:22


## 📗 IMAP Overview

If you have ever set up an email client or app, you will have certainly come across the terms `POP` and `IMAP`.
`IMAP-is short for Internet Message Access Protocol`, while `POP-translates to Post Office Protocol`. In other words, both are email protocols. You might listen about `Outlook`, `Thunderbird`, `Eudora`, `GNUMail`, `or (Mac) Mail` app which provides custom mail management services they download messages from your email account and to make changes like archiving messages or sorting them into folders and giving more personalization.


Essentially, the main difference of the two protocols is that POP downloads emails from the server for permanent local storage, while IMAP leaves them on the server and just caches (temporarily stores) emails locally. In other words, IMAP is a form of cloud storage.


### 📗 When Choose POP:-

- if you want to access your mail from only one single device.
- if need constant access to your email, regardless of internet availability.
- if you have limited server storage.

### 📗 When Choose IMAP:-

- if want to access your email from multiple different devices.
- if you have a reliable and constant internet connection.
- if you want to receive a quick overview of new emails or emails on the server.
- if local storage space is limited.
- if worried about backing your emails up.

If confused, then go with IMAP. It’s the more modern protocol, it allows you to be flexible, and your email is automatically backed up on the server. 

Today, we're going to look into IMAP, It's the open standard that describes how to access messages in an email mailbox. While we want to read and send mail programmatically, then IMAP is important. we just need an IMAP client with implemented on top of IMAP protocol standards.
 
 
Now let's deep dive into it. We’re going to connect to an email account, list all of the available folders in the mailbox, and download a message. Here, we are going to use `NodeJS IMAP Client` which will help us to explore,


## 📗 Enable IMAP permission for your E-Mail

- Log in your Gmail then, Open Email Setting, then Select `Forwarding and POP/IMAP` tab and change the status to `IMAP access: Status: IMAP is enabled`. To do so Select `Enable IMAP`. [After login into Gmail, Click Dynamic Link For Quick Access](https://mail.google.com/mail/u/0/#settings/fwdandpop).
- Now enable `Less Secure Apps: ON`. To do [After login into Gmail, Click Dynamic Link For Quick Access](https://myaccount.google.com/lesssecureapps).


## 🔰 Now, Setup IMAP Client

Here, I'm using nodejs client but you can use other language clients to achieve those features,

Before creating a node application make sure node is installed in your machine, You can find the installation guide from here [https://nodejs.org/en/download/].

    node --version
    npm --version


🔰Create a node application,

    mkdir imap-client-app
    npm init -y
    npm install --save imap
  
Note: NodeJs library [Node-IMAP Client at Github.](https://github.com/mscdex/node-imap)


## 📗 Take a look at implementation,

🔰 Now, create `manage-mailbox.js` files

```js
const Imap = require('imap'), inspect = require('util').inspect;


let getEmailFromInbox = (mailServer) => {
    mailServer.openBox('INBOX', true, function (err, box) {
        if (err) throw err;
        // we can define range '1:3'
        let f = mailServer.seq.fetch('1:*', {
            bodies: 'HEADER.FIELDS (FROM TO SUBJECT DATE)',
            struct: true
        });
        f.on('message', function (msg, seqno) {
            console.log('Message #%d', seqno);
            let prefix = '(#' + seqno + ') ';
            msg.on('body', function (stream, info) {
                let buffer = '';
                stream.on('data', function (chunk) {
                    buffer += chunk.toString('utf8');
                });
                stream.once('end', function () {
                    console.log(prefix + 'Parsed header: %s', inspect(Imap.parseHeader(buffer)));
                });
            });
        });
        f.once('error', function (err) {
            console.log('Fetch error: ' + err);
        });
        f.once('end', function () {
            console.log('Done fetching all messages!');
            //mailServer.end();
        });
    });
}

let createLabel = (mailServer, labelName) => {
    mailServer.addBox(labelName, (err) => {});
    console.log('message', 'New Label or Box Created');
}

let getMailboxStatusByName = (mailServer, inboxName) => {
    mailServer.status(inboxName, (err, mailbox) => {
        console.log('message', mailbox);
    });
    console.log('message', 'Label or Box Status');
}

let getMailBoxLabels = (mailServer) => {
    mailServer.getBoxes((error, mailbox) => {
        console.log('message', mailbox);
    })
}

let deleteLabel = (mailServer, labelName) => {
    mailServer.delBox(labelName, (error) => {})
   console.log('message', 'Label or Box removed');
}

let mailServer1 = new Imap({
    user: 'example@gmail.com',
    password: 'password',
    host: 'imap.gmail.com',
    port: 993,
    tls: true,
    tlsOptions: {
        rejectUnauthorized: false
    },
    authTimeout: 3000
}).once('error', function (err) {
    console.log('Source Server Error:- ', err);
});
mailServer1.once('ready', function () {
    mailServer1.openBox('INBOX', true, function (err, box) {
        if (err) throw err;
        console.log('message', 'server1 ready');
    });

    // mail operation
    getMailBoxLabels(mailServer1);
    getEmailFromInbox(mailServer1)
    createLabel(mailServer1, "demo-label1");
    deleteLabel(mailServer1, "demo-label1");
    getMailboxStatusByName(mailServer1, "INBOX");
})
mailServer1.connect();
```


🔰 To run that script, hit below command, see output

    node manage-mailbox.js

🔰 We can import and export email, one email server to another email server. To copy email create `copy-mailbox.js`,

```js
const Imap = require('imap'), inspect = require('util').inspect;

// Here, copy email source-mail-server to target-mail-server
let copyEmail = (srcServer1, srcServer2, emailServerName) => {
    srcServer1.search(['ALL'], (error, uids) => {
        //console.log('message', uids);
        var count = uids.length;
        var f = srcServer1.fetch(uids, { bodies: 'HEADER.FIELDS (FROM TO SUBJECT DATE)', struct: true });

        f.on('message', function (msg, seqno) {
            //console.log('Got a message with seq no: ' + seqno);

            var buffer = [], bufLen = 0, bufferText = '';
            msg.on('body', function (stream, info) {
                stream.on('data', function (chunk) {
                    bufferText += chunk.toString('utf8');
                    buffer.push(chunk);
                    bufLen += chunk.length;
                });
                stream.once('end', function () {
                    console.log('Parsed header: %s', inspect(Imap.parseHeader(bufferText)));                  // email contents
                    console.log(`====${emailServerName} - Finished message no. ${seqno} =======`);            // email email seqno
                
                    //console.log('message-binay-buffer', buffer);
                    //console.log('message-bufLen', bufLen);
                    //console.log('message-total-email-count', count);
                    
                    buffer = Buffer.concat(buffer, bufLen);
                    srcServer2.append(buffer, {
                        date: new Date(msg.date),
                        flags: ['Seen']
                    }, function (err) {
                        if (err) throw err;
                        if (--count === 0) {
                            console.log('Done copying!');
                            srcServer2.end()                    // close mail server1 connection
                            srcServer1.end()                    // close mail server2 connection
                        }
                    });

                });
            });
        });
        f.once('error', function (err) {
            console.log('Fetch error: ' + err);
        });
        f.once('end', function () {
            console.log('Done fetching all messages!');
        });
    });
};

let srcServer2 = new Imap({
    user: 'example-target@gmail.com',
    password: 'password',
    host: 'imap.gmail.com',
    port: 993,
    tls: true,
    tlsOptions: {
        rejectUnauthorized: false
    },
    authTimeout: 3000
}).once('error', function (err) {
    console.log('Target mail server error:- ', err);
});

srcServer2.once('ready', function () {
    srcServer2.openBox('INBOX', true, function (err, box) {
        if (err) throw err;
        console.log('message', 'Target mail server ready');
        let srcServer1 = new Imap({
            user: 'example-source@gmail.com',
            password: 'password',
            host: 'imap.gmail.com',
            port: 993,
            tls: true,
            tlsOptions: {
                rejectUnauthorized: false
            },
            authTimeout: 3000
        }).once('error', function (err) {
            console.log('Source Server Error:- ', err);
        });
        srcServer1.once('ready', function () {
            srcServer1.openBox('INBOX', true, function (err, box) {
                if (err) throw err;
                console.log('message', 'Source mail server ready');

                copyEmail(srcServer1, srcServer2, 'Server1');
            })
        });
        srcServer1.connect();
    });
})
srcServer2.connect();
```

🔰 To run that script, hit below command, see the output

    node copy-mailbox.js


>We’ve done it! you’ve learned major components of IMAP. We connected to an IMAP server, logged in to our email account, listed folders on the remote server, and downloaded message data, create a label, list of mail count. This is exactly what happens under the hood in email apps as you browse your mailbox.

## 📗 Bonus Section

🔰 Read Unseen email and update flag.

If, we like to parse email, use `Mailparser`. which is an advanced email parser for `Node.js`. Install package from here [https://nodemailer.com/extras/mailparser/]

    npm install mailparser --save

```js
// false = read only mood off, so after fetch we can update flag.
server.openBox('INBOX', false, function (err, box) {
    if (err) throw err;
    server.search(['UNSEEN'], function (err, results) {

        let f = server.fetch(results, {bodies: ''});
        const simpleParser = require('mailparser').simpleParser;

        f.on('message', function (msg, seqno) {
            let uid, headers, body = '';
            msg.on('body', function (stream, info) {
                simpleParser(stream, (err, parsed) => {
                    console.log(parsed.text)
                    console.log(parsed.textAsHtml)
                });
            });
            msg.once('attributes', function (attrs) {
                uid = attrs.uid;
                console.log(attrs);
            });
        });

        f.once("error", function (err) {
            return Promise.reject(err);
        });
    });
});
```


👌 Congratulations. & Thanks for your time & passion.
Feel free to comments, If you have any issues & queries.

### 🔰 References

- https://tools.ietf.org/html/rfc3501.html
- https://support.google.com/accounts/answer/6010255
- https://myaccount.google.com/lesssecureapps
- https://support.google.com/mail/answer/7126229
- https://github.com/mscdex/node-imap
- https://nodemailer.com/extras/mailparser/