基于Node.js开发Firebase云函数实现Gmail邮件监听及业务联动需求
基于Node.js Firebase云函数实现Gmail收件箱监听与Firestore联动方案
一、依赖安装与初始化
首先在Firebase云函数目录下安装所需依赖:
npm install firebase-functions firebase-admin imap mailparser nodemailer
初始化Firebase Admin SDK,用于操作Firestore和FCM:
const admin = require('firebase-admin'); admin.initializeApp(); const db = admin.firestore();
二、实现Gmail收件箱定时轮询(替代长连接)
由于云函数是无状态的,无法保持长期IMAP连接,因此采用定时轮询未读邮件的方案更可靠。以下是核心代码:
const Imap = require('imap'); const { simpleParser } = require('mailparser'); // Gmail IMAP配置 const imapConfig = { user: 'your-gmail@example.com', password: 'your-app-specific-password', // 开启2FA时用应用专用密码,否则用账户密码 host: 'imap.gmail.com', port: 993, tls: true, tlsOptions: { rejectUnauthorized: false } }; // 定时检查新邮件的云函数 exports.checkNewEmails = functions.runWith({ timeoutSeconds: 540, memory: '2GB' }).pubsub.schedule('every 1 minutes').onRun(async () => { await fetchAndProcessUnseenEmails(); return null; }); // 拉取并处理未读邮件 async function fetchAndProcessUnseenEmails() { const imap = new Imap(imapConfig); return new Promise((resolve, reject) => { imap.on('ready', () => { imap.openBox('INBOX', false, async (err) => { if (err) { imap.end(); return reject(err); } // 搜索未读邮件 imap.search(['UNSEEN'], async (err, results) => { if (err) { imap.end(); return reject(err); } if (results.length === 0) { imap.end(); return resolve(); } // 批量获取邮件内容 const fetch = imap.fetch(results, { bodies: '' }); fetch.on('message', (msg, seqno) => { msg.on('body', (stream) => { simpleParser(stream, async (err, parsedEmail) => { if (err) console.error('解析邮件失败:', err); else await processEmail(parsedEmail); // 标记邮件为已读 imap.addFlags(seqno, ['\\Seen'], (err) => { if (err) console.error('标记已读失败:', err); }); }); }); }); fetch.on('end', () => { imap.end(); resolve(); }); }); }); }); imap.on('error', (err) => { imap.end(); reject(err); }); imap.connect(); }); }
三、邮件主题解析与关联逻辑
核心是从邮件主题提取订单ID,或匹配现有工单,然后创建关联的Firestore文档:
async function processEmail(parsedEmail) { const subject = parsedEmail.subject; let orderId = null; let ticketId = null; // 1. 提取订单ID(根据实际主题格式调整正则) const orderMatch = subject.match(/订单 #(\d{5,})/i); // 示例:匹配"订单 #12345"格式 if (orderMatch) { orderId = orderMatch[1]; // 验证订单是否存在于Firestore const orderDoc = await db.collection('orders').doc(orderId).get(); if (!orderDoc.exists) orderId = null; } // 2. 无有效订单ID时,匹配现有工单 if (!orderId) { // 精确匹配工单主题(可根据需求改为模糊匹配) const ticketsSnapshot = await db.collection('tickets') .where('subject', '==', subject) .limit(1) .get(); if (!ticketsSnapshot.empty) { ticketId = ticketsSnapshot.docs[0].id; } else { // 无匹配工单时,自动创建新工单 const newTicket = await db.collection('tickets').add({ subject: subject, sender: parsedEmail.from.text, content: parsedEmail.text || parsedEmail.html, createdAt: admin.firestore.FieldValue.serverTimestamp() }); ticketId = newTicket.id; } } // 3. 创建关联的邮件记录文档 await db.collection('email_records').add({ subject: subject, sender: parsedEmail.from.text, content: parsedEmail.text || parsedEmail.html, createdAt: admin.firestore.FieldValue.serverTimestamp(), orderId: orderId || null, ticketId: ticketId || null }); // 4. 发送通知 await sendNotifications(orderId, ticketId, parsedEmail); }
四、发送FCM与邮件通知
实现FCM推送和邮件通知功能:
const nodemailer = require('nodemailer'); // 配置邮件发送器 const transporter = nodemailer.createTransport({ service: 'gmail', auth: { user: 'your-gmail@example.com', pass: 'your-app-specific-password' } }); async function sendNotifications(orderId, ticketId, parsedEmail) { // 1. 发送FCM通知 const fcmPayload = { notification: { title: '新邮件提醒', body: `收到与${orderId ? `订单#${orderId}` : `工单#${ticketId}`}相关的邮件` }, topic: 'email_alerts' // 可改为按订单/工单订阅的token发送 }; try { await admin.messaging().send(fcmPayload); console.log('FCM通知发送成功'); } catch (err) { console.error('FCM通知发送失败:', err); } // 2. 发送邮件通知(示例:发给客服) const mailOptions = { from: 'your-gmail@example.com', to: 'support@yourdomain.com', subject: `新邮件关联${orderId ? `订单#${orderId}` : `工单#${ticketId}`}`, text: `发件人:${parsedEmail.from.text}\n主题:${parsedEmail.subject}\n\n邮件内容:\n${parsedEmail.text}` }; try { await transporter.sendMail(mailOptions); console.log('邮件通知发送成功'); } catch (err) { console.error('邮件通知发送失败:', err); } }
五、部署与关键注意事项
- Gmail设置:登录Gmail账户,开启IMAP(设置→转发和POP/IMAP→启用IMAP);若开启两步验证,需在Google账户安全设置中生成应用专用密码替代普通密码。
- 云函数权限:确保云函数拥有Firestore读写权限及FCM发送权限,可通过Firebase控制台的IAM配置调整。
- 错误处理:建议在代码中添加更多try/catch块,避免单封邮件处理失败导致整个函数崩溃。
- 性能优化:若邮件量较大,可增加云函数内存配置(如升级到4GB),调整轮询频率(如每5分钟一次)。
- 部署命令:执行
firebase deploy --only functions部署云函数。
内容的提问来源于stack exchange,提问作者Mohamad Eizeddin
相关产品推荐
相关产品推荐

