11import axios from 'axios' ;
2+ import nodemailer from 'nodemailer' ;
23
34export default class MessageSender {
45 static TYPE = {
56 DINGDING : 0 ,
67 WECHAT : 1 ,
8+ QQEMAIL : 2 ,
79 // 未来可扩展更多类型...
810 } ;
911
1012 /**
1113 * 发送消息
12- * @param {string } text 消息文本
13- * @param {number } type 消息类型(0: 钉钉,1: 企业微信),默认 0
14+ * @param {string|object } text 消息文本(字符串或邮件配置对象)
15+ * @param {number } type 消息类型(0: 钉钉,1: 企业微信,2: QQ邮箱 ),默认 0
1416 */
1517 static async send ( text , type = MessageSender . TYPE . DINGDING ) {
16- if ( ! text || typeof text !== 'string' ) {
17- console . warn ( '[MessageSender] 消息内容必须是字符串' ) ;
18+ if ( ! text ) {
19+ console . warn ( '[MessageSender] 消息内容不能为空' ) ;
20+ return ;
21+ }
22+
23+ // QQ邮箱只允许对象,其他类型必须为字符串
24+ if ( type === MessageSender . TYPE . QQEMAIL && typeof text !== 'object' ) {
25+ console . warn ( '[MessageSender] QQ邮箱类型只支持配置对象' ) ;
26+ return ;
27+ }
28+
29+ if ( type !== MessageSender . TYPE . QQEMAIL && typeof text !== 'string' ) {
30+ console . warn ( '[MessageSender] 非邮箱类型消息内容必须是字符串' ) ;
1831 return ;
1932 }
2033
@@ -27,6 +40,10 @@ export default class MessageSender {
2740 await this . #sendWeChat( text ) ;
2841 break ;
2942
43+ case MessageSender . TYPE . QQEMAIL :
44+ await this . #sendQQEmail( text ) ;
45+ break ;
46+
3047 default :
3148 console . warn ( `[MessageSender] 不支持的消息类型: ${ type } ` ) ;
3249 }
@@ -65,4 +82,50 @@ export default class MessageSender {
6582 console . error ( '[MessageSender] 企业微信消息发送失败:' , err . message ) ;
6683 }
6784 }
85+
86+ /**
87+ * 发送QQ邮件(支持文本/HTML/多收件人)
88+ * @param {object } config 邮件配置对象
89+ * @property {string } [to] 收件人邮箱,默认使用环境变量QQ_EMAIL
90+ * @property {string } [subject] 邮件主题,默认"系统通知"
91+ * @property {string } [text] 纯文本内容
92+ * @property {string } [html] HTML内容
93+ * @property {Array } [attachments] 邮件附件
94+ */
95+ static async #sendQQEmail( config ) {
96+ const { QQ_EMAIL , QQ_SMTP_AUTH_CODE } = process . env ;
97+
98+ if ( ! QQ_EMAIL || ! QQ_SMTP_AUTH_CODE ) {
99+ console . log ( '[MessageSender] 未配置QQ邮箱或SMTP授权码,跳过邮件发送' ) ;
100+ return ;
101+ }
102+
103+ // 创建带连接池的邮件传输器
104+ const transporter = nodemailer . createTransport ( {
105+ //pool: true, // 启用连接池
106+ host : 'smtp.qq.com' ,
107+ port : 465 ,
108+ secure : true ,
109+ auth : {
110+ user : QQ_EMAIL ,
111+ pass : QQ_SMTP_AUTH_CODE
112+ }
113+ } ) ;
114+
115+ try {
116+ // 构建邮件选项,保护关键字段并提供默认值
117+ const mailOptions = {
118+ from : `"系统通知" <${ QQ_EMAIL } >` , // 固定发件人
119+ to : config . to || QQ_EMAIL , // 允许自定义收件人
120+ ...config
121+ } ;
122+
123+ const info = await transporter . sendMail ( mailOptions ) ;
124+ console . log ( '[MessageSender] QQ邮件已发送: %s' , info . accepted ) ;
125+ } catch ( err ) {
126+ console . error ( '[MessageSender] QQ邮件发送失败:' , err . message ) ;
127+ } finally {
128+ transporter . close ( ) ; // 关闭连接池
129+ }
130+ }
68131}
0 commit comments