import NodeIMAP from 'node-imap' import { createTransport, Transporter } from 'nodemailer' import { simpleParser } from 'mailparser' import { MailBot } from './bot' import { Adapter, Context, Universal } from '@satorijs/core' import { dispatchSession } from './utils' export class IMAP extends Adapter> { static reusable = true imap: NodeIMAP constructor(ctx: C, public bot: MailBot) { super(ctx) this.imap = new NodeIMAP({ user: bot.config.username, password: bot.config.password, host: bot.config.imap.host, port: bot.config.imap.port, tls: bot.config.imap.tls, }) this.imap.on('error', (error) => { bot.logger.error(error) }) } async connect(bot: MailBot) { this.imap.on('ready', () => { this.imap.openBox('INBOX', false, this.inbox.bind(this)) }) this.imap.on('close', () => { if (!bot.isActive) return bot.logger.info('IMAP disconnected, will reconnect in 3s...') bot.status = Universal.Status.RECONNECT setTimeout(() => { if (!bot.isActive) return this.imap.connect() }, 3000) }) this.imap.connect() } stop() { this.imap.end() } inbox(error: Error) { if (error) { this.bot.logger.error(error) return } this.bot.online() this.scan() this.imap.on('mail', this.scan.bind(this)) } scan() { this.imap.search(['UNSEEN'], (error, uids) => { if (error) { this.bot.logger.error(error) return } if (uids.length === 0) return this.imap.setFlags(uids, ['\\SEEN'], (error) => { if (error) this.bot.logger.error(error) }) // markSeen doesn't work const mails = this.imap.fetch(uids, { bodies: '' }) mails.on('message', message => { message.once('body', (stream) => { simpleParser(stream, (error, mail) => { if (error) { this.bot.logger.error(error) return } dispatchSession(this.bot, mail) }) }) }) }) } } export interface Attachment { filename?: string content: Buffer contentType: string cid?: string } export interface SendOptions { to: string html: string attachments?: Attachment[] subject?: string inReplyTo?: string } export class SMTP { transporter: Transporter from: string constructor(config: MailBot.Config) { this.transporter = createTransport({ host: config.smtp.host, port: config.smtp.port, secure: config.smtp.tls, auth: { user: config.username, pass: config.password, }, }) const address = config.selfId || config.username this.from = config.name ? `${config.name} <${address}>` : address } async send(options: SendOptions): Promise { const info = await this.transporter.sendMail({ ...options, from: this.from, }) return info.messageId } }