发送邮件正文图片链接改为内置附件
This commit is contained in:
@@ -54,7 +54,7 @@
|
|||||||
<el-tooltip v-if="item.status === 2" effect="dark" :content="$t('delivered')">
|
<el-tooltip v-if="item.status === 2" effect="dark" :content="$t('delivered')">
|
||||||
<Icon icon="bi:send-check-fill" style="color: #51C76B" width="20" height="20"/>
|
<Icon icon="bi:send-check-fill" style="color: #51C76B" width="20" height="20"/>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip v-if="item.status === 3" effect="dark" :content="$t('bounced')">
|
<el-tooltip v-if="item.status === 3 || item.status === 8" effect="dark" :content="$t('bounced')">
|
||||||
<Icon icon="bi:send-x-fill" style="color: #F56C6C" width="20" height="20"/>
|
<Icon icon="bi:send-x-fill" style="color: #F56C6C" width="20" height="20"/>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip v-if="item.status === 4" effect="dark" :content="$t('complained')">
|
<el-tooltip v-if="item.status === 4" effect="dark" :content="$t('complained')">
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ function updateContent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
img:not(table img) {
|
img:not(table img) {
|
||||||
max-width: 100% !important;
|
max-width: 100%;
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -96,6 +96,8 @@ function initEditor() {
|
|||||||
statusbar: false,
|
statusbar: false,
|
||||||
height: "100%",
|
height: "100%",
|
||||||
auto_focus: true,
|
auto_focus: true,
|
||||||
|
relative_urls: false, //阻止 img标签域名和网站域名相同 自动把链接转换相对路径
|
||||||
|
remove_script_host: false, // 阻止删除 URL 中的域名
|
||||||
forced_root_block: 'div',
|
forced_root_block: 'div',
|
||||||
skin: `${uiStore.dark ? 'oxide-dark' : 'oxide'}`,
|
skin: `${uiStore.dark ? 'oxide-dark' : 'oxide'}`,
|
||||||
content_css: `/tinymce/css/index.css,${uiStore.dark ? 'dark' : 'default'}`,
|
content_css: `/tinymce/css/index.css,${uiStore.dark ? 'dark' : 'default'}`,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
"i18next": "^25.3.2",
|
"i18next": "^25.3.2",
|
||||||
"linkedom": "^0.18.10",
|
"linkedom": "^0.18.10",
|
||||||
"postal-mime": "^2.4.3",
|
"postal-mime": "^2.4.3",
|
||||||
"resend": "^4.5.1",
|
"resend": "^6.4.1",
|
||||||
"ua-parser-js": "^2.0.3",
|
"ua-parser-js": "^2.0.3",
|
||||||
"uuid": "^11.1.0"
|
"uuid": "^11.1.0"
|
||||||
}
|
}
|
||||||
|
|||||||
122
mail-worker/pnpm-lock.yaml
generated
122
mail-worker/pnpm-lock.yaml
generated
@@ -13,7 +13,7 @@ importers:
|
|||||||
version: 3.882.0
|
version: 3.882.0
|
||||||
'@cloudflare/vite-plugin':
|
'@cloudflare/vite-plugin':
|
||||||
specifier: 1.6.0
|
specifier: 1.6.0
|
||||||
version: 1.6.0(rollup@4.50.0)(vite@6.3.5(@types/node@24.3.0))(workerd@1.20250310.0)(wrangler@4.33.1)
|
version: 1.6.0(rollup@4.50.0)(vite@6.3.5(@types/node@24.3.0))(workerd@1.20250823.0)(wrangler@4.33.1)
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.13
|
specifier: ^1.11.13
|
||||||
version: 1.11.18
|
version: 1.11.18
|
||||||
@@ -33,8 +33,8 @@ importers:
|
|||||||
specifier: ^2.4.3
|
specifier: ^2.4.3
|
||||||
version: 2.4.4
|
version: 2.4.4
|
||||||
resend:
|
resend:
|
||||||
specifier: ^4.5.1
|
specifier: ^6.4.1
|
||||||
version: 4.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
version: 6.4.1(@react-email/render@1.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1))
|
||||||
ua-parser-js:
|
ua-parser-js:
|
||||||
specifier: ^2.0.3
|
specifier: ^2.0.3
|
||||||
version: 2.0.4
|
version: 2.0.4
|
||||||
@@ -1416,12 +1416,18 @@ packages:
|
|||||||
'@speed-highlight/core@1.2.7':
|
'@speed-highlight/core@1.2.7':
|
||||||
resolution: {integrity: sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==}
|
resolution: {integrity: sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==}
|
||||||
|
|
||||||
|
'@stablelib/base64@1.0.1':
|
||||||
|
resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==}
|
||||||
|
|
||||||
'@types/estree@1.0.8':
|
'@types/estree@1.0.8':
|
||||||
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||||
|
|
||||||
'@types/node-fetch@2.6.13':
|
'@types/node-fetch@2.6.13':
|
||||||
resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==}
|
resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==}
|
||||||
|
|
||||||
|
'@types/node@22.19.0':
|
||||||
|
resolution: {integrity: sha512-xpr/lmLPQEj+TUnHmR+Ab91/glhJvsqcjB+yY0Ix9GO70H6Lb4FHH5GeqdOE5btAx7eIMwuHkp4H2MSkLcqWbA==}
|
||||||
|
|
||||||
'@types/node@24.3.0':
|
'@types/node@24.3.0':
|
||||||
resolution: {integrity: sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==}
|
resolution: {integrity: sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==}
|
||||||
|
|
||||||
@@ -1726,6 +1732,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
|
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
es6-promise@4.2.8:
|
||||||
|
resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==}
|
||||||
|
|
||||||
esbuild@0.17.19:
|
esbuild@0.17.19:
|
||||||
resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==}
|
resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@@ -1768,6 +1777,9 @@ packages:
|
|||||||
fast-deep-equal@2.0.1:
|
fast-deep-equal@2.0.1:
|
||||||
resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==}
|
resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==}
|
||||||
|
|
||||||
|
fast-sha256@1.3.0:
|
||||||
|
resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==}
|
||||||
|
|
||||||
fast-xml-parser@5.2.5:
|
fast-xml-parser@5.2.5:
|
||||||
resolution: {integrity: sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==}
|
resolution: {integrity: sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -1980,6 +1992,9 @@ packages:
|
|||||||
printable-characters@1.0.42:
|
printable-characters@1.0.42:
|
||||||
resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==}
|
resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==}
|
||||||
|
|
||||||
|
querystringify@2.2.0:
|
||||||
|
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
|
||||||
|
|
||||||
react-dom@19.1.1:
|
react-dom@19.1.1:
|
||||||
resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==}
|
resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1992,9 +2007,17 @@ packages:
|
|||||||
resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==}
|
resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
resend@4.8.0:
|
requires-port@1.0.0:
|
||||||
resolution: {integrity: sha512-R8eBOFQDO6dzRTDmaMEdpqrkmgSjPpVXt4nGfWsZdYOet0kqra0xgbvTES6HmCriZEXbmGk3e0DiGIaLFTFSHA==}
|
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
|
||||||
|
|
||||||
|
resend@6.4.1:
|
||||||
|
resolution: {integrity: sha512-+P1gF6bYT0lKd0vsYyKKTHd6PfMH37yDgNRA6wAARQgQbYlc2BZYuo9sB/uZKkVg1oGSh0cgpnxNKGsZJutXMg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
peerDependencies:
|
||||||
|
'@react-email/render': '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@react-email/render':
|
||||||
|
optional: true
|
||||||
|
|
||||||
rollup-plugin-inject@3.0.2:
|
rollup-plugin-inject@3.0.2:
|
||||||
resolution: {integrity: sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==}
|
resolution: {integrity: sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==}
|
||||||
@@ -2064,6 +2087,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-5eG9FQjEjDbAlI5+kdpdyPIBMRH4GfTVDGREVupaZHmVoppknhM29b/S9BkQz7cathp85BVgRi/As3Siln7e0Q==}
|
resolution: {integrity: sha512-5eG9FQjEjDbAlI5+kdpdyPIBMRH4GfTVDGREVupaZHmVoppknhM29b/S9BkQz7cathp85BVgRi/As3Siln7e0Q==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
svix@1.76.1:
|
||||||
|
resolution: {integrity: sha512-CRuDWBTgYfDnBLRaZdKp9VuoPcNUq9An14c/k+4YJ15Qc5Grvf66vp0jvTltd4t7OIRj+8lM1DAgvSgvf7hdLw==}
|
||||||
|
|
||||||
tinybench@2.9.0:
|
tinybench@2.9.0:
|
||||||
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
|
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
|
||||||
|
|
||||||
@@ -2105,6 +2131,9 @@ packages:
|
|||||||
uhyphen@0.2.0:
|
uhyphen@0.2.0:
|
||||||
resolution: {integrity: sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==}
|
resolution: {integrity: sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==}
|
||||||
|
|
||||||
|
undici-types@6.21.0:
|
||||||
|
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||||
|
|
||||||
undici-types@7.10.0:
|
undici-types@7.10.0:
|
||||||
resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==}
|
resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==}
|
||||||
|
|
||||||
@@ -2125,6 +2154,13 @@ packages:
|
|||||||
unenv@2.0.0-rc.19:
|
unenv@2.0.0-rc.19:
|
||||||
resolution: {integrity: sha512-t/OMHBNAkknVCI7bVB9OWjUUAwhVv9vsPIAGnNUxnu3FxPQN11rjh0sksLMzc3g7IlTgvHmOTl4JM7JHpcv5wA==}
|
resolution: {integrity: sha512-t/OMHBNAkknVCI7bVB9OWjUUAwhVv9vsPIAGnNUxnu3FxPQN11rjh0sksLMzc3g7IlTgvHmOTl4JM7JHpcv5wA==}
|
||||||
|
|
||||||
|
url-parse@1.5.10:
|
||||||
|
resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
|
||||||
|
|
||||||
|
uuid@10.0.0:
|
||||||
|
resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
uuid@11.1.0:
|
uuid@11.1.0:
|
||||||
resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==}
|
resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -2766,11 +2802,11 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
workerd: 1.20250310.0
|
workerd: 1.20250310.0
|
||||||
|
|
||||||
'@cloudflare/unenv-preset@2.3.2(unenv@2.0.0-rc.17)(workerd@1.20250310.0)':
|
'@cloudflare/unenv-preset@2.3.2(unenv@2.0.0-rc.17)(workerd@1.20250823.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
unenv: 2.0.0-rc.17
|
unenv: 2.0.0-rc.17
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
workerd: 1.20250310.0
|
workerd: 1.20250823.0
|
||||||
|
|
||||||
'@cloudflare/unenv-preset@2.7.0(unenv@2.0.0-rc.19)(workerd@1.20250823.0)':
|
'@cloudflare/unenv-preset@2.7.0(unenv@2.0.0-rc.19)(workerd@1.20250823.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -2778,9 +2814,9 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
workerd: 1.20250823.0
|
workerd: 1.20250823.0
|
||||||
|
|
||||||
'@cloudflare/vite-plugin@1.6.0(rollup@4.50.0)(vite@6.3.5(@types/node@24.3.0))(workerd@1.20250310.0)(wrangler@4.33.1)':
|
'@cloudflare/vite-plugin@1.6.0(rollup@4.50.0)(vite@6.3.5(@types/node@24.3.0))(workerd@1.20250823.0)(wrangler@4.33.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@cloudflare/unenv-preset': 2.3.2(unenv@2.0.0-rc.17)(workerd@1.20250310.0)
|
'@cloudflare/unenv-preset': 2.3.2(unenv@2.0.0-rc.17)(workerd@1.20250823.0)
|
||||||
'@mjackson/node-fetch-server': 0.6.1
|
'@mjackson/node-fetch-server': 0.6.1
|
||||||
'@rollup/plugin-replace': 6.0.2(rollup@4.50.0)
|
'@rollup/plugin-replace': 6.0.2(rollup@4.50.0)
|
||||||
get-port: 7.1.0
|
get-port: 7.1.0
|
||||||
@@ -3205,6 +3241,7 @@ snapshots:
|
|||||||
react: 19.1.1
|
react: 19.1.1
|
||||||
react-dom: 19.1.1(react@19.1.1)
|
react-dom: 19.1.1(react@19.1.1)
|
||||||
react-promise-suspense: 0.3.4
|
react-promise-suspense: 0.3.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@rollup/plugin-replace@6.0.2(rollup@4.50.0)':
|
'@rollup/plugin-replace@6.0.2(rollup@4.50.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3288,6 +3325,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
domhandler: 5.0.3
|
domhandler: 5.0.3
|
||||||
selderee: 0.11.0
|
selderee: 0.11.0
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@sindresorhus/is@7.0.2': {}
|
'@sindresorhus/is@7.0.2': {}
|
||||||
|
|
||||||
@@ -3782,6 +3820,8 @@ snapshots:
|
|||||||
|
|
||||||
'@speed-highlight/core@1.2.7': {}
|
'@speed-highlight/core@1.2.7': {}
|
||||||
|
|
||||||
|
'@stablelib/base64@1.0.1': {}
|
||||||
|
|
||||||
'@types/estree@1.0.8': {}
|
'@types/estree@1.0.8': {}
|
||||||
|
|
||||||
'@types/node-fetch@2.6.13':
|
'@types/node-fetch@2.6.13':
|
||||||
@@ -3789,6 +3829,10 @@ snapshots:
|
|||||||
'@types/node': 24.3.0
|
'@types/node': 24.3.0
|
||||||
form-data: 4.0.4
|
form-data: 4.0.4
|
||||||
|
|
||||||
|
'@types/node@22.19.0':
|
||||||
|
dependencies:
|
||||||
|
undici-types: 6.21.0
|
||||||
|
|
||||||
'@types/node@24.3.0':
|
'@types/node@24.3.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 7.10.0
|
undici-types: 7.10.0
|
||||||
@@ -3926,7 +3970,8 @@ snapshots:
|
|||||||
|
|
||||||
deep-eql@5.0.2: {}
|
deep-eql@5.0.2: {}
|
||||||
|
|
||||||
deepmerge@4.3.1: {}
|
deepmerge@4.3.1:
|
||||||
|
optional: true
|
||||||
|
|
||||||
defu@6.1.4: {}
|
defu@6.1.4: {}
|
||||||
|
|
||||||
@@ -3987,6 +4032,8 @@ snapshots:
|
|||||||
has-tostringtag: 1.0.2
|
has-tostringtag: 1.0.2
|
||||||
hasown: 2.0.2
|
hasown: 2.0.2
|
||||||
|
|
||||||
|
es6-promise@4.2.8: {}
|
||||||
|
|
||||||
esbuild@0.17.19:
|
esbuild@0.17.19:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@esbuild/android-arm': 0.17.19
|
'@esbuild/android-arm': 0.17.19
|
||||||
@@ -4085,7 +4132,10 @@ snapshots:
|
|||||||
|
|
||||||
exsolve@1.0.7: {}
|
exsolve@1.0.7: {}
|
||||||
|
|
||||||
fast-deep-equal@2.0.1: {}
|
fast-deep-equal@2.0.1:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
fast-sha256@1.3.0: {}
|
||||||
|
|
||||||
fast-xml-parser@5.2.5:
|
fast-xml-parser@5.2.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -4158,6 +4208,7 @@ snapshots:
|
|||||||
dom-serializer: 2.0.0
|
dom-serializer: 2.0.0
|
||||||
htmlparser2: 8.0.2
|
htmlparser2: 8.0.2
|
||||||
selderee: 0.11.0
|
selderee: 0.11.0
|
||||||
|
optional: true
|
||||||
|
|
||||||
htmlparser2@10.0.0:
|
htmlparser2@10.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -4172,6 +4223,7 @@ snapshots:
|
|||||||
domhandler: 5.0.3
|
domhandler: 5.0.3
|
||||||
domutils: 3.2.2
|
domutils: 3.2.2
|
||||||
entities: 4.5.0
|
entities: 4.5.0
|
||||||
|
optional: true
|
||||||
|
|
||||||
i18next@25.4.2:
|
i18next@25.4.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -4183,7 +4235,8 @@ snapshots:
|
|||||||
|
|
||||||
kleur@4.1.5: {}
|
kleur@4.1.5: {}
|
||||||
|
|
||||||
leac@0.6.0: {}
|
leac@0.6.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
linkedom@0.18.12:
|
linkedom@0.18.12:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -4286,6 +4339,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
leac: 0.6.0
|
leac: 0.6.0
|
||||||
peberminta: 0.9.0
|
peberminta: 0.9.0
|
||||||
|
optional: true
|
||||||
|
|
||||||
path-to-regexp@6.3.0: {}
|
path-to-regexp@6.3.0: {}
|
||||||
|
|
||||||
@@ -4293,7 +4347,8 @@ snapshots:
|
|||||||
|
|
||||||
pathval@2.0.1: {}
|
pathval@2.0.1: {}
|
||||||
|
|
||||||
peberminta@0.9.0: {}
|
peberminta@0.9.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
picocolors@1.1.1: {}
|
picocolors@1.1.1: {}
|
||||||
|
|
||||||
@@ -4307,27 +4362,34 @@ snapshots:
|
|||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
source-map-js: 1.2.1
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
prettier@3.6.2: {}
|
prettier@3.6.2:
|
||||||
|
optional: true
|
||||||
|
|
||||||
printable-characters@1.0.42: {}
|
printable-characters@1.0.42: {}
|
||||||
|
|
||||||
|
querystringify@2.2.0: {}
|
||||||
|
|
||||||
react-dom@19.1.1(react@19.1.1):
|
react-dom@19.1.1(react@19.1.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 19.1.1
|
react: 19.1.1
|
||||||
scheduler: 0.26.0
|
scheduler: 0.26.0
|
||||||
|
optional: true
|
||||||
|
|
||||||
react-promise-suspense@0.3.4:
|
react-promise-suspense@0.3.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
fast-deep-equal: 2.0.1
|
fast-deep-equal: 2.0.1
|
||||||
|
optional: true
|
||||||
|
|
||||||
react@19.1.1: {}
|
react@19.1.1:
|
||||||
|
optional: true
|
||||||
|
|
||||||
resend@4.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
|
requires-port@1.0.0: {}
|
||||||
|
|
||||||
|
resend@6.4.1(@react-email/render@1.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)):
|
||||||
dependencies:
|
dependencies:
|
||||||
|
svix: 1.76.1
|
||||||
|
optionalDependencies:
|
||||||
'@react-email/render': 1.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
'@react-email/render': 1.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||||
transitivePeerDependencies:
|
|
||||||
- react
|
|
||||||
- react-dom
|
|
||||||
|
|
||||||
rollup-plugin-inject@3.0.2:
|
rollup-plugin-inject@3.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -4370,11 +4432,13 @@ snapshots:
|
|||||||
'@rollup/rollup-win32-x64-msvc': 4.50.0
|
'@rollup/rollup-win32-x64-msvc': 4.50.0
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
|
|
||||||
scheduler@0.26.0: {}
|
scheduler@0.26.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
selderee@0.11.0:
|
selderee@0.11.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
parseley: 0.12.1
|
parseley: 0.12.1
|
||||||
|
optional: true
|
||||||
|
|
||||||
semver@7.7.2: {}
|
semver@7.7.2: {}
|
||||||
|
|
||||||
@@ -4431,6 +4495,15 @@ snapshots:
|
|||||||
|
|
||||||
supports-color@10.2.0: {}
|
supports-color@10.2.0: {}
|
||||||
|
|
||||||
|
svix@1.76.1:
|
||||||
|
dependencies:
|
||||||
|
'@stablelib/base64': 1.0.1
|
||||||
|
'@types/node': 22.19.0
|
||||||
|
es6-promise: 4.2.8
|
||||||
|
fast-sha256: 1.3.0
|
||||||
|
url-parse: 1.5.10
|
||||||
|
uuid: 10.0.0
|
||||||
|
|
||||||
tinybench@2.9.0: {}
|
tinybench@2.9.0: {}
|
||||||
|
|
||||||
tinyexec@0.3.2: {}
|
tinyexec@0.3.2: {}
|
||||||
@@ -4466,6 +4539,8 @@ snapshots:
|
|||||||
|
|
||||||
uhyphen@0.2.0: {}
|
uhyphen@0.2.0: {}
|
||||||
|
|
||||||
|
undici-types@6.21.0: {}
|
||||||
|
|
||||||
undici-types@7.10.0: {}
|
undici-types@7.10.0: {}
|
||||||
|
|
||||||
undici@5.29.0:
|
undici@5.29.0:
|
||||||
@@ -4498,6 +4573,13 @@ snapshots:
|
|||||||
pathe: 2.0.3
|
pathe: 2.0.3
|
||||||
ufo: 1.6.1
|
ufo: 1.6.1
|
||||||
|
|
||||||
|
url-parse@1.5.10:
|
||||||
|
dependencies:
|
||||||
|
querystringify: 2.2.0
|
||||||
|
requires-port: 1.0.0
|
||||||
|
|
||||||
|
uuid@10.0.0: {}
|
||||||
|
|
||||||
uuid@11.1.0: {}
|
uuid@11.1.0: {}
|
||||||
|
|
||||||
uuid@9.0.1: {}
|
uuid@9.0.1: {}
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ export const emailConst = {
|
|||||||
COMPLAINED: 4,
|
COMPLAINED: 4,
|
||||||
DELAYED: 5,
|
DELAYED: 5,
|
||||||
SAVING: 6,
|
SAVING: 6,
|
||||||
NOONE: 7
|
NOONE: 7,
|
||||||
|
FAILED: 8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import orm from '../entity/orm';
|
import orm from '../entity/orm';
|
||||||
import { att } from '../entity/att';
|
import { att } from '../entity/att';
|
||||||
import { and, eq, isNull, inArray } from 'drizzle-orm';
|
import { and, eq, isNull, inArray, desc } from 'drizzle-orm';
|
||||||
import r2Service from './r2-service';
|
import r2Service from './r2-service';
|
||||||
import constant from '../const/constant';
|
import constant from '../const/constant';
|
||||||
import fileUtils from '../utils/file-utils';
|
import fileUtils from '../utils/file-utils';
|
||||||
import { attConst } from '../const/entity-const';
|
import { attConst } from '../const/entity-const';
|
||||||
import { parseHTML } from 'linkedom';
|
import { parseHTML } from 'linkedom';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import domainUtils from '../utils/domain-uitls';
|
import domainUtils from '../utils/domain-uitls';
|
||||||
import BizError from '../error/biz-error';
|
import settingService from "./setting-service";
|
||||||
|
|
||||||
const attService = {
|
const attService = {
|
||||||
|
|
||||||
@@ -46,22 +47,27 @@ const attService = {
|
|||||||
).all();
|
).all();
|
||||||
},
|
},
|
||||||
|
|
||||||
async toImageUrlHtml(c, content, r2Domain) {
|
async toImageUrlHtml(c, content) {
|
||||||
|
|
||||||
|
const { r2Domain } = await settingService.query(c);
|
||||||
|
|
||||||
const { document } = parseHTML(content);
|
const { document } = parseHTML(content);
|
||||||
|
|
||||||
const images = Array.from(document.querySelectorAll('img'));
|
const images = Array.from(document.querySelectorAll('img'));
|
||||||
|
|
||||||
const attDataList = [];
|
let imageDataList = [];
|
||||||
|
|
||||||
for (const img of images) {
|
for (const img of images) {
|
||||||
|
|
||||||
|
//邮件正文base64图片转cid附件
|
||||||
const src = img.getAttribute('src');
|
const src = img.getAttribute('src');
|
||||||
if (src && src.startsWith('data:image')) {
|
if (src && src.startsWith('data:image')) {
|
||||||
const file = fileUtils.base64ToFile(src);
|
const file = fileUtils.base64ToFile(src);
|
||||||
const buff = await file.arrayBuffer();
|
const buff = await file.arrayBuffer();
|
||||||
|
const cid = uuidv4().replace(/-/g, '');
|
||||||
const key = constant.ATTACHMENT_PREFIX + await fileUtils.getBuffHash(buff) + fileUtils.getExtFileName(file.name);
|
const key = constant.ATTACHMENT_PREFIX + await fileUtils.getBuffHash(buff) + fileUtils.getExtFileName(file.name);
|
||||||
img.setAttribute('src', domainUtils.toOssDomain(r2Domain) + '/' + key);
|
|
||||||
|
img.setAttribute('src', 'cid:' + cid);
|
||||||
|
|
||||||
const attData = {};
|
const attData = {};
|
||||||
attData.key = key;
|
attData.key = key;
|
||||||
@@ -69,8 +75,24 @@ const attService = {
|
|||||||
attData.mimeType = file.type;
|
attData.mimeType = file.type;
|
||||||
attData.size = file.size;
|
attData.size = file.size;
|
||||||
attData.buff = buff;
|
attData.buff = buff;
|
||||||
|
attData.content = fileUtils.base64ToDataStr(src);
|
||||||
|
attData.contentId = cid;
|
||||||
|
|
||||||
attDataList.push(attData);
|
imageDataList.push(attData);
|
||||||
|
}
|
||||||
|
|
||||||
|
//邮件正文站内图片转cid附件
|
||||||
|
if (src && src.startsWith(domainUtils.toOssDomain(r2Domain))) {
|
||||||
|
|
||||||
|
const cid = uuidv4().replace(/-/g, '')
|
||||||
|
img.setAttribute('src', 'cid:' + cid);
|
||||||
|
|
||||||
|
const attData = {};
|
||||||
|
attData.key = src.replace(domainUtils.toOssDomain(r2Domain) + '/','');
|
||||||
|
attData.path = src;
|
||||||
|
attData.contentId = cid;
|
||||||
|
attData.type = attConst.type.EMBED;
|
||||||
|
imageDataList.push(attData);
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasInlineWidth = img.hasAttribute('width');
|
const hasInlineWidth = img.hasAttribute('width');
|
||||||
@@ -82,7 +104,26 @@ const attService = {
|
|||||||
img.setAttribute('style', newStyle);
|
img.setAttribute('style', newStyle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { attDataList, html: document.toString() };
|
|
||||||
|
//查询已有内嵌url图片信息
|
||||||
|
const keys = [...new Set(imageDataList.filter(item => item.path).map(item => item.key))];
|
||||||
|
const dbImageList = await this.selectOneByKeys(c, keys);
|
||||||
|
|
||||||
|
//设置给当前附件
|
||||||
|
imageDataList.forEach(image => {
|
||||||
|
dbImageList.forEach(dbImage => {
|
||||||
|
if (image.path && (image.key === dbImage.key)) {
|
||||||
|
image.size = dbImage.size;
|
||||||
|
image.filename = dbImage.filename;
|
||||||
|
image.mimeType = dbImage.mimeType;
|
||||||
|
image.contentType = dbImage.mimeType;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
imageDataList = imageDataList.filter(image => !image.path || image.size);
|
||||||
|
|
||||||
|
return { imageDataList, html: document.toString() };
|
||||||
},
|
},
|
||||||
|
|
||||||
async saveSendAtt(c, attList, userId, accountId, emailId) {
|
async saveSendAtt(c, attList, userId, accountId, emailId) {
|
||||||
@@ -194,8 +235,14 @@ const attService = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async removeByAccountId(c, accountId) {
|
async removeByAccountId(c, accountId) {
|
||||||
console.log(accountId)
|
|
||||||
await this.removeAttByField(c, "account_id", [accountId])
|
await this.removeAttByField(c, "account_id", [accountId])
|
||||||
|
},
|
||||||
|
|
||||||
|
selectOneByKeys(c, keys) {
|
||||||
|
if (!keys || keys.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return orm(c).select().from(att).where(inArray(att.key, keys)).orderBy(desc(att.attId)).groupBy(att.key).all();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ const emailService = {
|
|||||||
|
|
||||||
const { resendTokens, r2Domain, send } = await settingService.query(c);
|
const { resendTokens, r2Domain, send } = await settingService.query(c);
|
||||||
|
|
||||||
let { attDataList, html } = await attService.toImageUrlHtml(c, content, r2Domain);
|
let { imageDataList, html } = await attService.toImageUrlHtml(c, content);
|
||||||
|
|
||||||
if (send === settingConst.send.CLOSE) {
|
if (send === settingConst.send.CLOSE) {
|
||||||
throw new BizError(t('disabledSend'), 403);
|
throw new BizError(t('disabledSend'), 403);
|
||||||
@@ -173,11 +173,11 @@ const emailService = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (attDataList.length > 0 && !r2Domain) {
|
if (imageDataList.length > 0 && !r2Domain) {
|
||||||
throw new BizError(t('noOsDomainSendPic'));
|
throw new BizError(t('noOsDomainSendPic'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attDataList.length > 0 && !await r2Service.hasOSS(c)) {
|
if (imageDataList.length > 0 && !await r2Service.hasOSS(c)) {
|
||||||
throw new BizError(t('noOsSendPic'));
|
throw new BizError(t('noOsSendPic'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,6 +242,7 @@ const emailService = {
|
|||||||
|
|
||||||
const resend = new Resend(resendToken);
|
const resend = new Resend(resendToken);
|
||||||
|
|
||||||
|
//如果是分开发送
|
||||||
if (manyType === 'divide') {
|
if (manyType === 'divide') {
|
||||||
|
|
||||||
let sendFormList = [];
|
let sendFormList = [];
|
||||||
@@ -275,7 +276,7 @@ const emailService = {
|
|||||||
subject: subject,
|
subject: subject,
|
||||||
text: text,
|
text: text,
|
||||||
html: html,
|
html: html,
|
||||||
attachments: attachments
|
attachments: [...imageDataList, ...attachments]
|
||||||
};
|
};
|
||||||
|
|
||||||
if (sendType === 'reply') {
|
if (sendType === 'reply') {
|
||||||
@@ -296,7 +297,10 @@ const emailService = {
|
|||||||
throw new BizError(error.message);
|
throw new BizError(error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
html = this.imgReplace(html, null, r2Domain);
|
imageDataList = imageDataList.map(item => ({...item, contentId: `<${item.contentId}>`}))
|
||||||
|
|
||||||
|
//把图片标签cid标签切换会通用url
|
||||||
|
html = this.imgReplace(html, imageDataList, r2Domain);
|
||||||
|
|
||||||
const emailData = {};
|
const emailData = {};
|
||||||
emailData.sendEmail = accountRow.email;
|
emailData.sendEmail = accountRow.email;
|
||||||
@@ -348,11 +352,12 @@ const emailService = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const emailRowList = await Promise.all(
|
const emailRowList = await Promise.all(
|
||||||
|
|
||||||
emailDataList.map(async (emailData) => {
|
emailDataList.map(async (emailData) => {
|
||||||
const emailRow = await orm(c).insert(email).values(emailData).returning().get();
|
const emailRow = await orm(c).insert(email).values(emailData).returning().get();
|
||||||
|
|
||||||
if (attDataList.length > 0) {
|
if (imageDataList.length > 0) {
|
||||||
await attService.saveArticleAtt(c, attDataList, userId, accountId, emailRow.emailId);
|
await attService.saveArticleAtt(c, imageDataList, userId, accountId, emailRow.emailId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attachments?.length > 0 && await r2Service.hasOSS(c)) {
|
if (attachments?.length > 0 && await r2Service.hasOSS(c)) {
|
||||||
|
|||||||
@@ -34,6 +34,12 @@ const resendService = {
|
|||||||
params.message = null
|
params.message = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (body.type === 'email.failed') {
|
||||||
|
params.status = emailConst.status.FAILED
|
||||||
|
params.resendEmailId = body.data.email_id
|
||||||
|
params.message = body.data.failed.reason
|
||||||
|
}
|
||||||
|
|
||||||
const emailRow = await emailService.updateEmailStatus(c, params)
|
const emailRow = await emailService.updateEmailStatus(c, params)
|
||||||
|
|
||||||
if (!emailRow) {
|
if (!emailRow) {
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ const fileUtils = {
|
|||||||
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
base64ToDataStr(base64) {
|
||||||
|
return base64.split(',')[1] || base64;
|
||||||
|
},
|
||||||
|
|
||||||
base64ToUint8Array(base64) {
|
base64ToUint8Array(base64) {
|
||||||
const binaryStr = atob(base64);
|
const binaryStr = atob(base64);
|
||||||
const len = binaryStr.length;
|
const len = binaryStr.length;
|
||||||
|
|||||||
Reference in New Issue
Block a user