Commit 540f321f by Archer Committed by GitHub

Test email plugin (#4387)

* add email plugin (#4343)

* add email plugin

* remove console.log

---------

Co-authored-by: zhengshuai.li <zhengshuai.li@cloudpense.com>

* perf: smtp email

---------

Co-authored-by: lzs2000131 <lzs2000131@163.com>
Co-authored-by: zhengshuai.li <zhengshuai.li@cloudpense.com>
parent a37c7515
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
"dependencies": { "dependencies": {
"cheerio": "1.0.0-rc.12", "cheerio": "1.0.0-rc.12",
"@types/pg": "^8.6.6", "@types/pg": "^8.6.6",
"@types/nodemailer": "^6.4.17",
"axios": "^1.8.2", "axios": "^1.8.2",
"duck-duck-scrape": "^2.2.5", "duck-duck-scrape": "^2.2.5",
"echarts": "5.4.1", "echarts": "5.4.1",
...@@ -13,6 +14,7 @@ ...@@ -13,6 +14,7 @@
"mssql": "^11.0.1", "mssql": "^11.0.1",
"mysql2": "^3.11.3", "mysql2": "^3.11.3",
"json5": "^2.2.3", "json5": "^2.2.3",
"nodemailer": "^6.10.0",
"pg": "^8.10.0", "pg": "^8.10.0",
"wikijs": "^6.4.1" "wikijs": "^6.4.1"
}, },
......
...@@ -29,7 +29,8 @@ const packagePluginList = [ ...@@ -29,7 +29,8 @@ const packagePluginList = [
'databaseConnection', 'databaseConnection',
'Doc2X', 'Doc2X',
'Doc2X/PDF2text', 'Doc2X/PDF2text',
'searchXNG' 'searchXNG',
'smtpEmail'
]; ];
export const list = [...staticPluginList, ...packagePluginList]; export const list = [...staticPluginList, ...packagePluginList];
......
import { getErrText } from '@fastgpt/global/common/error/utils';
import nodemailer from 'nodemailer';
interface Props {
// SMTP配置
smtpHost: string;
smtpPort: string;
SSL: boolean;
smtpUser: string;
smtpPass: string;
fromName?: string;
// 邮件参数
to: string;
subject: string;
content: string;
cc?: string;
bcc?: string;
attachments?: string;
}
interface Response {
success: boolean;
messageId?: string;
error?: string;
}
const validateEmail = (email: string) => {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
};
const validateEmails = (emails: string) => {
return emails.split(',').every((email) => validateEmail(email.trim()));
};
const main = async ({
smtpHost,
smtpPort,
SSL,
smtpUser,
smtpPass,
fromName,
to,
subject,
content,
cc,
bcc,
attachments
}: Props): Promise<Response> => {
try {
// 验证SMTP配置
if (!smtpHost || !smtpPort || !smtpUser || !smtpPass) {
throw new Error('Incomplete SMTP configuration');
}
// 验证必填参数
if (!to || !subject || !content) {
throw new Error('Recipient, subject, and content are required');
}
// 验证邮箱格式
if (!validateEmails(to)) {
throw new Error('Invalid recipient email format');
}
if (cc && !validateEmails(cc)) {
throw new Error('Invalid CC email format');
}
if (bcc && !validateEmails(bcc)) {
throw new Error('Invalid BCC email format');
}
// 创建SMTP传输对象
const transporter = nodemailer.createTransport({
host: smtpHost,
port: Number(smtpPort),
secure: SSL === true,
auth: {
user: smtpUser,
pass: smtpPass
}
});
let attachmentsArray = [];
try {
attachmentsArray = JSON.parse(attachments || '[]');
} catch (error) {
throw new Error('Attachment format parsing error, please check attachment configuration');
}
// 发送邮件
const info = await transporter.sendMail({
from: `"${fromName || 'FastGPT'}" <${smtpUser}>`,
to: to
.split(',')
.map((email) => email.trim())
.join(','),
cc: cc
?.split(',')
.map((email) => email.trim())
.join(','),
bcc: bcc
?.split(',')
.map((email) => email.trim())
.join(','),
subject,
html: content,
attachments: attachmentsArray || []
});
return {
success: true,
messageId: info.messageId
};
} catch (error: any) {
return {
success: false,
error: getErrText(error)
};
}
};
export default main;
...@@ -423,6 +423,7 @@ export const iconPaths = { ...@@ -423,6 +423,7 @@ export const iconPaths = {
'plugins/dingding': () => import('./icons/plugins/dingding.svg'), 'plugins/dingding': () => import('./icons/plugins/dingding.svg'),
'plugins/doc2x': () => import('./icons/plugins/doc2x.svg'), 'plugins/doc2x': () => import('./icons/plugins/doc2x.svg'),
'plugins/qiwei': () => import('./icons/plugins/qiwei.svg'), 'plugins/qiwei': () => import('./icons/plugins/qiwei.svg'),
'plugins/email': () => import('./icons/plugins/email.svg'),
'plugins/textEditor': () => import('./icons/plugins/textEditor.svg'), 'plugins/textEditor': () => import('./icons/plugins/textEditor.svg'),
point: () => import('./icons/point.svg'), point: () => import('./icons/point.svg'),
preview: () => import('./icons/preview.svg'), preview: () => import('./icons/preview.svg'),
......
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1739434077659" class="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="1659"
xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200">
<path d="M102.4 409.6h819.2v409.6a102.4 102.4 0 0 1-102.4 102.4H204.8a102.4 102.4 0 0 1-102.4-102.4V409.6zM102.4 409.6h819.2L579.4816 110.1824a102.4 102.4 0 0 0-134.9632 0z" fill="#36C196" p-id="1660"></path>
<path d="M204.8 204.8h614.4a51.2 51.2 0 0 1 51.2 51.2v563.2H153.6V256a51.2 51.2 0 0 1 51.2-51.2z" fill="#FFBA40" p-id="1661"></path>
<path d="M316.5184 307.2m0 25.6l0 153.6q0 25.6-25.6 25.6l0 0q-25.6 0-25.6-25.6l0-153.6q0-25.6 25.6-25.6l0 0q25.6 0 25.6 25.6Z" fill="#FFFFFF" p-id="1662"></path>
<path d="M460.288 307.2m25.6 0l256 0q25.6 0 25.6 25.6l0 0q0 25.6-25.6 25.6l-256 0q-25.6 0-25.6-25.6l0 0q0-25.6 25.6-25.6Z" fill="#FFFFFF" p-id="1663"></path>
<path d="M613.888 409.6m25.6 0l102.4 0q25.6 0 25.6 25.6l0 0q0 25.6-25.6 25.6l-102.4 0q-25.6 0-25.6-25.6l0 0q0-25.6 25.6-25.6Z" fill="#FFFFFF" p-id="1664"></path>
<path d="M102.4 409.6v409.6a102.4 102.4 0 0 0 102.4 102.4h563.2z" fill="#2A44A1" p-id="1665"></path>
<path d="M921.6 409.6v409.6a102.4 102.4 0 0 1-102.4 102.4H256z" fill="#3D60F6" p-id="1666"></path>
</svg>
\ No newline at end of file
...@@ -96,6 +96,9 @@ importers: ...@@ -96,6 +96,9 @@ importers:
packages/plugins: packages/plugins:
dependencies: dependencies:
'@types/nodemailer':
specifier: ^6.4.17
version: 6.4.17
'@types/pg': '@types/pg':
specifier: ^8.6.6 specifier: ^8.6.6
version: 8.11.11 version: 8.11.11
...@@ -126,6 +129,9 @@ importers: ...@@ -126,6 +129,9 @@ importers:
mysql2: mysql2:
specifier: ^3.11.3 specifier: ^3.11.3
version: 3.13.0 version: 3.13.0
nodemailer:
specifier: ^6.10.0
version: 6.10.0
pg: pg:
specifier: ^8.10.0 specifier: ^8.10.0
version: 8.14.0 version: 8.14.0
...@@ -3301,6 +3307,9 @@ packages: ...@@ -3301,6 +3307,9 @@ packages:
'@types/node@20.17.24': '@types/node@20.17.24':
resolution: {integrity: sha512-d7fGCyB96w9BnWQrOsJtpyiSaBcAYYr75bnK6ZRjDbql2cGLj/3GsL5OYmLPNq76l7Gf2q4Rv9J2o6h5CrD9sA==} resolution: {integrity: sha512-d7fGCyB96w9BnWQrOsJtpyiSaBcAYYr75bnK6ZRjDbql2cGLj/3GsL5OYmLPNq76l7Gf2q4Rv9J2o6h5CrD9sA==}
'@types/nodemailer@6.4.17':
resolution: {integrity: sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww==}
'@types/nprogress@0.2.3': '@types/nprogress@0.2.3':
resolution: {integrity: sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA==} resolution: {integrity: sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA==}
...@@ -7267,6 +7276,10 @@ packages: ...@@ -7267,6 +7276,10 @@ packages:
engines: {node: '>=10.0.0'} engines: {node: '>=10.0.0'}
hasBin: true hasBin: true
nodemailer@6.10.0:
resolution: {integrity: sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA==}
engines: {node: '>=6.0.0'}
non-layered-tidy-tree-layout@2.0.2: non-layered-tidy-tree-layout@2.0.2:
resolution: {integrity: sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==} resolution: {integrity: sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==}
...@@ -12513,6 +12526,10 @@ snapshots: ...@@ -12513,6 +12526,10 @@ snapshots:
dependencies: dependencies:
undici-types: 6.19.8 undici-types: 6.19.8
'@types/nodemailer@6.4.17':
dependencies:
'@types/node': 20.17.24
'@types/nprogress@0.2.3': {} '@types/nprogress@0.2.3': {}
'@types/papaparse@5.3.7': '@types/papaparse@5.3.7':
...@@ -17630,6 +17647,8 @@ snapshots: ...@@ -17630,6 +17647,8 @@ snapshots:
dependencies: dependencies:
xlsx: https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz xlsx: https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz
nodemailer@6.10.0: {}
non-layered-tidy-tree-layout@2.0.2: {} non-layered-tidy-tree-layout@2.0.2: {}
nopt@5.0.0: nopt@5.0.0:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment