简体   繁体   中英

How to mark a specific mail as read using node-imap

I develop both the frontend and backend of a custom intern application, in which you can receive and read mails using the node-imap package.

There is a property you can set so that whenever an unread mail is fetched it gets set as read, but this is not what I want to do: I don't want mails to be marked as read when they are received, but rather when the user clicks on a mail to open it (kind of like gmail).

The solution I have thought about was:

  1. Client connects and asks for mails
  2. Fetch mails in NodeJS, and associate every one of them with its UID
  3. The client receives the mail with its header, body and its UID
  4. When user opens an unread mail, client sends a request to the server with the mail's UID
  5. In the backend, fetch the mail by this UID
  6. Mark it as read using node-imap

The problem is: there seems to be no way to directly associate a messageId with its UID, because the mail itself and its UID are accessible by two different streams:

imap.openBox('INBOX', true, () => {
    imap.search(['ALL'], (err, results) => {
        const f = imap.fetch(results, {bodies: ''})
        f.on('message', msg => {
            msg.on('body', (stream, info) => {
                // here you can parse and read the mail's headers, content etc...
            })

            msg.on('attributes', attrs => {
                // here you can get the mail's UID via attrs
            })
        })
    })
})

Because these two streams are not synchronous (so the UID could arrive when the data of another mail is being streamed for example), and don't have any related data besides the date, I don't know how to link a mail to its UID and in the end just merge these two data.

I have thought about using the seqno, but becaue of its ever changing nature it is not reliable (it changes whenever a new mail arrives, or another one gets deleted).

Would you know any solution that could solve my problem ? Should I rely on the date attribute to associate an UID to its mail ? Thank you

I have found an answer to my problem !

There is no need to actually bind an email to its UID, you can retrieve emails by their messageId. Here is how you can set a single email as read:

async function setEmailRead (messageId) {
    const imap = new Imap(imapConfig)
    imap.once('ready', () => {
        imap.openBox('INBOX', false, () => {
 
            // here is how you fetch a single email by its messageId
            const criteria = ["HEADER", "message-id", messageId]

            imap.search([criteria], (err, results) => {
                if (err || results.length === 0) {
                    throw "No email found for this ID"
                }

                // set mail as read
                imap.setFlags(results, ['\\Seen'], err => {
                    if (err) {
                        throw err
                    }
                })
            })
        })
    })

    imap.once('error', err => {})
    imap.once('close', () => {})
    imap.connect()
}

I hope this will be useful to somebody in the future :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM