mirror of
https://github.com/eoao/cloud-mail.git
synced 2026-05-06 13:41:43 +08:00
优化站内发件无需第三方
This commit is contained in:
@@ -183,7 +183,6 @@ const en = {
|
||||
optional: 'Optional',
|
||||
subjectInputDesc: 'Please enter the email subject',
|
||||
changeUserName: 'Change Username',
|
||||
sendSeparately: 'Separately',
|
||||
send: 'Send',
|
||||
reply: 'Reply',
|
||||
confirm: 'Confirm',
|
||||
|
||||
@@ -183,7 +183,6 @@ const zh = {
|
||||
optional: '可选',
|
||||
subjectInputDesc: '请输入邮件主题',
|
||||
changeUserName: '修改用户名',
|
||||
sendSeparately: '分别发送',
|
||||
send: '发送',
|
||||
reply: '回复',
|
||||
confirm: '确定',
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<el-input-tag @add-tag="addTagChange" tag-type="primary" @input="inputChange" size="default" v-model="form.receiveEmail"
|
||||
:placeholder="ruleEmailsInputDesc">
|
||||
<el-input-tag @add-tag="addTagChange" tag-type="primary" @input="inputChange" size="default" v-model="form.receiveEmail" >
|
||||
<template #prefix>
|
||||
<div class="item-title" >{{ $t('recipient') }}</div>
|
||||
<el-select
|
||||
@@ -37,18 +36,12 @@
|
||||
</el-select>
|
||||
</template>
|
||||
<template #suffix>
|
||||
<div style="display: flex;">
|
||||
<div style="display: flex;margin-right: 3px;">
|
||||
<Icon icon="fa7-solid:user-plus" width="20" height="20" class="add-contact" @click.stop="openContacts" />
|
||||
</div>
|
||||
<span class="distribute" :class="form.manyType ? 'checked' : ''"
|
||||
@click.stop="checkDistribute">{{ $t('sendSeparately') }}</span>
|
||||
</template>
|
||||
</el-input-tag>
|
||||
<el-input v-model="form.subject" :placeholder="$t('subjectInputDesc')">
|
||||
<template #prefix>
|
||||
<div class="item-title">{{ $t('subject') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input v-model="form.subject" :placeholder="t('subject')" />
|
||||
<tinyEditor :def-value="defValue" ref="editor" @change="change" @focus="focusChange" />
|
||||
<div class="button-item">
|
||||
<div class="att-add" @click="chooseFile">
|
||||
@@ -141,7 +134,6 @@ const contactsTabRef = ref({})
|
||||
const showContacts = ref(false)
|
||||
const mySelect = ref()
|
||||
let selectStatus = false
|
||||
const ruleEmailsInputDesc = ref(t('ruleEmailsInputDesc'))
|
||||
const backReply = reactive({
|
||||
receiveEmail: [],
|
||||
subject: '',
|
||||
@@ -152,7 +144,6 @@ const form = reactive({
|
||||
sendEmail: '',
|
||||
receiveEmail: [],
|
||||
accountId: -1,
|
||||
manyType: null,
|
||||
name: '',
|
||||
subject: '',
|
||||
content: '',
|
||||
@@ -255,10 +246,6 @@ function addTagChange(val) {
|
||||
if (selectStatus && has) openSelect()
|
||||
}
|
||||
|
||||
function checkDistribute() {
|
||||
form.manyType = form.manyType ? null : 'divide'
|
||||
}
|
||||
|
||||
function clearContent() {
|
||||
ElMessageBox.confirm(t('clearContentConfirm'), {
|
||||
confirmButtonText: t('confirm'),
|
||||
@@ -447,7 +434,11 @@ function openReply(email) {
|
||||
email.subject = email.subject || ''
|
||||
|
||||
form.receiveEmail.push(email.sendEmail)
|
||||
form.subject = (email.subject.startsWith('Re:') || email.subject.startsWith('回复:')) ? email.subject : 'Re: ' + email.subject
|
||||
form.subject = (
|
||||
email.subject.startsWith('Re:') ||
|
||||
email.subject.startsWith('Re:') ||
|
||||
email.subject.startsWith('回复:') ||
|
||||
email.subject.startsWith('回复:')) ? email.subject : 'Re:' + email.subject
|
||||
form.sendType = 'reply'
|
||||
form.emailId = email.emailId
|
||||
|
||||
@@ -651,21 +642,6 @@ function close() {
|
||||
grid-template-rows: auto auto 1fr auto;
|
||||
gap: 15px;
|
||||
|
||||
.distribute {
|
||||
color: var(--el-color-info);
|
||||
background: var(--el-color-info-light-9);
|
||||
border: var(--el-color-info-light-8);
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.distribute.checked {
|
||||
background: var(--el-color-primary-light-9);
|
||||
color: var(--el-color-primary) !important;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,9 @@ import settingService from '../service/setting-service';
|
||||
import attService from '../service/att-service';
|
||||
import constant from '../const/constant';
|
||||
import fileUtils from '../utils/file-utils';
|
||||
import { emailConst, isDel, roleConst, settingConst } from '../const/entity-const';
|
||||
import { emailConst, isDel, settingConst } from '../const/entity-const';
|
||||
import emailUtils from '../utils/email-utils';
|
||||
import roleService from '../service/role-service';
|
||||
import verifyUtils from '../utils/verify-utils';
|
||||
import userService from '../service/user-service';
|
||||
import telegramService from '../service/telegram-service';
|
||||
|
||||
@@ -60,45 +59,16 @@ export async function email(message, env, ctx) {
|
||||
|
||||
if (account && userRow.email !== env.admin) {
|
||||
|
||||
let { banEmail, banEmailType, availDomain } = await roleService.selectByUserId({ env: env }, account.userId);
|
||||
let { banEmail, availDomain } = await roleService.selectByUserId({ env: env }, account.userId);
|
||||
|
||||
if (!roleService.hasAvailDomainPerm(availDomain, message.to)) {
|
||||
message.setReject('Mailbox disabled');
|
||||
message.setReject('The recipient is not authorized to use this domain.');
|
||||
return;
|
||||
}
|
||||
|
||||
banEmail = banEmail.split(',').filter(item => item !== '');
|
||||
|
||||
|
||||
if (banEmail.includes('*')) {
|
||||
|
||||
if (!banEmailHandler(banEmailType, message, email)) return;
|
||||
|
||||
}
|
||||
|
||||
for (const item of banEmail) {
|
||||
|
||||
if (verifyUtils.isDomain(item)) {
|
||||
|
||||
const banDomain = item.toLowerCase();
|
||||
const receiveDomain = emailUtils.getDomain(email.from.address.toLowerCase());
|
||||
|
||||
if (banDomain === receiveDomain) {
|
||||
|
||||
if (!banEmailHandler(banEmailType, message, email)) return;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (item.toLowerCase() === email.from.address.toLowerCase()) {
|
||||
|
||||
if (!banEmailHandler(banEmailType, message, email)) return;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(roleService.isBanEmail(banEmail, email.from.address)) {
|
||||
message.setReject('The recipient is disabled from receiving emails.');
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -199,20 +169,3 @@ export async function email(message, env, ctx) {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
function banEmailHandler(banEmailType, message, email) {
|
||||
|
||||
if (banEmailType === roleConst.banEmailType.ALL) {
|
||||
message.setReject('Mailbox disabled');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (banEmailType === roleConst.banEmailType.CONTENT) {
|
||||
email.html = 'The content has been deleted';
|
||||
email.text = 'The content has been deleted';
|
||||
email.attachments = [];
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { sqliteTable, integer, text } from 'drizzle-orm/sqlite-core';
|
||||
import { sql } from 'drizzle-orm';
|
||||
|
||||
export const att = sqliteTable('attachments', {
|
||||
export const att = sqliteTable('attachments', {
|
||||
attId: integer('att_id').primaryKey({ autoIncrement: true }),
|
||||
userId: integer('user_id').notNull(),
|
||||
emailId: integer('email_id').notNull(),
|
||||
|
||||
@@ -15,7 +15,6 @@ const en = {
|
||||
noOsDomainSendAtt: 'Cannot send attachments: object storage domain not configured',
|
||||
noOsSendAtt: 'Cannot send attachments: object storage not configured',
|
||||
disabledSend: 'Email sending feature is disabled',
|
||||
noSeparateSend: 'Attachments are not supported in separate sending',
|
||||
daySendLimit: 'Daily send limit reached',
|
||||
totalSendLimit: 'Total send limit reached',
|
||||
daySendLack: 'Not enough remaining sends today',
|
||||
|
||||
@@ -15,7 +15,6 @@ const zh = {
|
||||
noOsDomainSendAtt: '对象存储域名未配置不能发送附件',
|
||||
noOsSendAtt: '对象存储未配置不能发送附件',
|
||||
disabledSend: '邮件发送功能已停用',
|
||||
noSeparateSend: '分别发送暂时不支持附件',
|
||||
daySendLimit: '发送次数已到达每日限制',
|
||||
totalSendLimit: '发送次数已到达限制',
|
||||
daySendLack: '当日剩余发送次数不足',
|
||||
|
||||
@@ -171,6 +171,9 @@ const attService = {
|
||||
attData.emailId = emailId;
|
||||
attData.accountId = accountId;
|
||||
attData.type = attConst.type.EMBED;
|
||||
if (!attData.buff) {
|
||||
continue;
|
||||
}
|
||||
await r2Service.putObj(c, attData.key, attData.buff, {
|
||||
contentType: attData.mimeType,
|
||||
cacheControl: `max-age=259200`,
|
||||
|
||||
@@ -19,7 +19,8 @@ import kvConst from '../const/kv-const';
|
||||
import { t } from '../i18n/i18n'
|
||||
import domainUtils from '../utils/domain-uitls';
|
||||
import account from "../entity/account";
|
||||
import {sleep} from "../utils/time-utils";
|
||||
import { att } from '../entity/att';
|
||||
import telegramService from './telegram-service';
|
||||
|
||||
const emailService = {
|
||||
|
||||
@@ -147,25 +148,26 @@ const emailService = {
|
||||
return orm(c).insert(email).values({ ...params }).returning().get();
|
||||
},
|
||||
|
||||
//邮件发送
|
||||
async send(c, params, userId) {
|
||||
|
||||
let {
|
||||
accountId,
|
||||
name,
|
||||
sendType,
|
||||
emailId,
|
||||
receiveEmail,
|
||||
manyType,
|
||||
text,
|
||||
content,
|
||||
subject,
|
||||
attachments
|
||||
accountId, //发送账号id
|
||||
name, //发件人名字
|
||||
sendType, //发件类型
|
||||
emailId, //邮件id,如果是回复邮件会带
|
||||
receiveEmail, //收件人邮箱
|
||||
text, //邮件纯文本
|
||||
content, //邮件内容
|
||||
subject, //邮件标题
|
||||
attachments //附件
|
||||
} = params;
|
||||
|
||||
const { resendTokens, r2Domain, send } = await settingService.query(c);
|
||||
const { resendTokens, r2Domain, send, domainList } = await settingService.query(c);
|
||||
|
||||
let { imageDataList, html } = await attService.toImageUrlHtml(c, content);
|
||||
|
||||
//判断是否关闭发件功能
|
||||
if (send === settingConst.send.CLOSE) {
|
||||
throw new BizError(t('disabledSend'), 403);
|
||||
}
|
||||
@@ -173,10 +175,12 @@ const emailService = {
|
||||
const userRow = await userService.selectById(c, userId);
|
||||
const roleRow = await roleService.selectById(c, userRow.type);
|
||||
|
||||
//如果不是管理员,发送被禁用
|
||||
if (c.env.admin !== userRow.email && roleRow.sendType === 'ban') {
|
||||
throw new BizError(t('bannedSend'), 403);
|
||||
}
|
||||
|
||||
//如果不是管理员,权限设置了发送次数
|
||||
if (c.env.admin !== userRow.email && roleRow.sendCount) {
|
||||
|
||||
if (userRow.sendCount >= roleRow.sendCount) {
|
||||
@@ -191,11 +195,6 @@ const emailService = {
|
||||
|
||||
}
|
||||
|
||||
if (attachments.length > 0 && manyType === 'divide') {
|
||||
throw new BizError(t('noSeparateSend'));
|
||||
}
|
||||
|
||||
|
||||
const accountRow = await accountService.selectById(c, accountId);
|
||||
|
||||
if (!accountRow) {
|
||||
@@ -207,21 +206,28 @@ const emailService = {
|
||||
}
|
||||
|
||||
if (c.env.admin !== userRow.email) {
|
||||
|
||||
//用户没有这个域名的使用权限
|
||||
if(!roleService.hasAvailDomainPerm(roleRow.availDomain, accountRow.email)) {
|
||||
throw new BizError(t('noDomainPermSend'),403)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//判断接收方是不是全部为站内邮箱
|
||||
const allInternal = receiveEmail.every(email => {
|
||||
const domain = '@' + emailUtils.getDomain(email);
|
||||
return domainList.includes(domain);
|
||||
});
|
||||
|
||||
const domain = emailUtils.getDomain(accountRow.email);
|
||||
const resendToken = resendTokens[domain];
|
||||
|
||||
if (!resendToken) {
|
||||
//如果接收方存在站外邮箱,又没有resend token
|
||||
if (!resendToken && !allInternal) {
|
||||
throw new BizError(t('noResendToken'));
|
||||
}
|
||||
|
||||
|
||||
//没有发件人名字自动截取
|
||||
if (!name) {
|
||||
name = emailUtils.getName(accountRow.email);
|
||||
}
|
||||
@@ -230,6 +236,7 @@ const emailService = {
|
||||
messageId: null
|
||||
};
|
||||
|
||||
//如果是回复邮件
|
||||
if (sendType === 'reply') {
|
||||
|
||||
emailRow = await this.selectById(c, emailId);
|
||||
@@ -240,37 +247,12 @@ const emailService = {
|
||||
|
||||
}
|
||||
|
||||
let resendResult = null;
|
||||
let resendResult = {};
|
||||
|
||||
const resend = new Resend(resendToken);
|
||||
//存在站外时邮箱全部由resend发送
|
||||
if (!allInternal) {
|
||||
|
||||
//如果是分开发送
|
||||
if (manyType === 'divide') {
|
||||
|
||||
let sendFormList = [];
|
||||
|
||||
receiveEmail.forEach(email => {
|
||||
const sendForm = {
|
||||
from: `${name} <${accountRow.email}>`,
|
||||
to: [email],
|
||||
subject: subject,
|
||||
text: text,
|
||||
html: html
|
||||
};
|
||||
|
||||
if (sendType === 'reply') {
|
||||
sendForm.headers = {
|
||||
'in-reply-to': emailRow.messageId,
|
||||
'references': emailRow.messageId
|
||||
};
|
||||
}
|
||||
|
||||
sendFormList.push(sendForm);
|
||||
});
|
||||
|
||||
resendResult = await resend.batch.send(sendFormList);
|
||||
|
||||
} else {
|
||||
const resend = new Resend(resendToken);
|
||||
|
||||
const sendForm = {
|
||||
from: `${name} <${accountRow.email}>`,
|
||||
@@ -304,6 +286,7 @@ const emailService = {
|
||||
//把图片标签cid标签切换会通用url
|
||||
html = this.imgReplace(html, imageDataList, r2Domain);
|
||||
|
||||
//封装数据保存到数据库
|
||||
const emailData = {};
|
||||
emailData.sendEmail = accountRow.email;
|
||||
emailData.name = name;
|
||||
@@ -311,72 +294,54 @@ const emailService = {
|
||||
emailData.content = html;
|
||||
emailData.text = text;
|
||||
emailData.accountId = accountId;
|
||||
emailData.status = emailConst.status.SENT;
|
||||
emailData.type = emailConst.type.SEND;
|
||||
emailData.userId = userId;
|
||||
emailData.status = emailConst.status.SENT;
|
||||
emailData.resendEmailId = data?.id;
|
||||
|
||||
const emailDataList = [];
|
||||
const recipient = [];
|
||||
|
||||
if (manyType === 'divide') {
|
||||
receiveEmail.forEach(item => {
|
||||
recipient.push({ address: item, name: '' });
|
||||
});
|
||||
|
||||
receiveEmail.forEach((item, index) => {
|
||||
const emailDataItem = { ...emailData };
|
||||
emailDataItem.resendEmailId = data.data[index].id;
|
||||
emailDataItem.recipient = JSON.stringify([{ address: item, name: '' }]);
|
||||
emailDataList.push(emailDataItem);
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
emailData.resendEmailId = data.id;
|
||||
|
||||
const recipient = [];
|
||||
|
||||
receiveEmail.forEach(item => {
|
||||
recipient.push({ address: item, name: '' });
|
||||
});
|
||||
|
||||
emailData.recipient = JSON.stringify(recipient);
|
||||
|
||||
emailDataList.push(emailData);
|
||||
}
|
||||
emailData.recipient = JSON.stringify(recipient);
|
||||
|
||||
if (sendType === 'reply') {
|
||||
emailDataList.forEach(emailData => {
|
||||
emailData.inReplyTo = emailRow.messageId;
|
||||
emailData.relation = emailRow.messageId;
|
||||
});
|
||||
emailData.inReplyTo = emailRow.messageId;
|
||||
emailData.relation = emailRow.messageId;
|
||||
}
|
||||
|
||||
|
||||
//如果权限有发送次数增加用户发送次数
|
||||
if (roleRow.sendCount) {
|
||||
await userService.incrUserSendCount(c, receiveEmail.length, userId);
|
||||
}
|
||||
|
||||
const emailRowList = await Promise.all(
|
||||
//保存到数据库并返回结果
|
||||
const emailResult = await orm(c).insert(email).values(emailData).returning().get();
|
||||
|
||||
emailDataList.map(async (emailData) => {
|
||||
const emailRow = await orm(c).insert(email).values(emailData).returning().get();
|
||||
//保存内嵌附件
|
||||
if (imageDataList.length > 0) {
|
||||
await attService.saveArticleAtt(c, imageDataList, userId, accountId, emailResult.emailId);
|
||||
}
|
||||
|
||||
if (imageDataList.length > 0) {
|
||||
await attService.saveArticleAtt(c, imageDataList, userId, accountId, emailRow.emailId);
|
||||
}
|
||||
//保存普通附件
|
||||
if (attachments?.length > 0) {
|
||||
await attService.saveSendAtt(c, attachments, userId, accountId, emailResult.emailId);
|
||||
}
|
||||
|
||||
if (attachments?.length > 0) {
|
||||
await attService.saveSendAtt(c, attachments, userId, accountId, emailRow.emailId);
|
||||
}
|
||||
const attList = await attService.selectByEmailIds(c, [emailResult.emailId]);
|
||||
emailResult.attList = attList;
|
||||
|
||||
const attsList = await attService.selectByEmailIds(c, [emailRow.emailId]);
|
||||
emailRow.attList = attsList;
|
||||
|
||||
return emailRow;
|
||||
})
|
||||
);
|
||||
//如果全是站内接收方,直接写入数据库
|
||||
if (allInternal) {
|
||||
await this.HandleOnSiteEmail(c, receiveEmail, emailResult, attList);
|
||||
}
|
||||
|
||||
const dateStr = dayjs().format('YYYY-MM-DD');
|
||||
|
||||
let daySendTotal = await c.env.kv.get(kvConst.SEND_DAY_COUNT + dateStr);
|
||||
|
||||
//记录每天发件次数统计
|
||||
if (!daySendTotal) {
|
||||
await c.env.kv.put(kvConst.SEND_DAY_COUNT + dateStr, JSON.stringify(receiveEmail.length), { expirationTtl: 60 * 60 * 24 });
|
||||
} else {
|
||||
@@ -384,7 +349,117 @@ const emailService = {
|
||||
await c.env.kv.put(kvConst.SEND_DAY_COUNT + dateStr, JSON.stringify(daySendTotal), { expirationTtl: 60 * 60 * 24 });
|
||||
}
|
||||
|
||||
return emailRowList;
|
||||
return [ emailResult ];
|
||||
},
|
||||
|
||||
//处理站内邮件发送
|
||||
async HandleOnSiteEmail(c, receiveEmail, sendEmailData, attList) {
|
||||
|
||||
const { noRecipient } = await settingService.query(c);
|
||||
|
||||
//查询所有收件人账号信息
|
||||
let accountList = await orm(c).select().from(account).where(inArray(account.email, receiveEmail)).all();
|
||||
|
||||
//查询所有收件人权限身份
|
||||
const userIds = accountList.map(accountRow => accountRow.userId);
|
||||
let roleList = await roleService.selectByUserIds(c, userIds);
|
||||
|
||||
//封装数据库准备保存到数据库
|
||||
const emailDataList = [];
|
||||
|
||||
for (const email of receiveEmail) {
|
||||
|
||||
//把发件人邮件改成收件
|
||||
const emailValues = {...sendEmailData}
|
||||
emailValues.status = emailConst.status.RECEIVE;
|
||||
emailValues.type = emailConst.type.RECEIVE;
|
||||
emailValues.toEmail = email;
|
||||
emailValues.toName = emailUtils.getName(email);
|
||||
emailValues.emailId = null;
|
||||
|
||||
const accountRow = accountList.find(accountRow => accountRow.email === email);
|
||||
|
||||
//如果收件人存在就把邮件信息改成收件人的
|
||||
if (accountRow) {
|
||||
|
||||
//设置给收件人保存
|
||||
emailValues.userId = accountRow.userId;
|
||||
emailValues.accountId = accountRow.accountId;
|
||||
emailValues.type = emailConst.type.RECEIVE;
|
||||
emailValues.status = emailConst.status.RECEIVE;
|
||||
|
||||
const roleRow = roleList.find(roleRow => roleRow.userId === accountRow.userId);
|
||||
|
||||
let { banEmail, availDomain } = roleRow;
|
||||
|
||||
//如果收件人没有这个域名的使用权限和有邮件拦截,就把邮件改为拒收状态
|
||||
if (email !== c.env.admin) {
|
||||
|
||||
if (!roleService.hasAvailDomainPerm(availDomain, email)) {
|
||||
emailValues.status = emailConst.status.BOUNCED;
|
||||
emailValues.message = `The recipient <${email}> is not authorized to use this domain.`;
|
||||
} else if(roleService.isBanEmail(banEmail, sendEmailData.sendEmail)) {
|
||||
emailValues.status = emailConst.status.BOUNCED;
|
||||
emailValues.message = `The recipient <${email}> is disabled from receiving emails.`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
emailDataList.push(emailValues);
|
||||
|
||||
} else {
|
||||
|
||||
//设置无收件人邮件信息
|
||||
emailValues.userId = 0;
|
||||
emailValues.accountId = 0;
|
||||
emailValues.type = emailConst.type.RECEIVE;
|
||||
emailValues.status = emailConst.status.NOONE;
|
||||
|
||||
//如果无人收件关闭改为拒收
|
||||
if (noRecipient === settingConst.noRecipient.CLOSE) {
|
||||
emailValues.status = emailConst.status.BOUNCED;
|
||||
emailValues.message = `Recipient not found: <${email}>`;
|
||||
}
|
||||
|
||||
emailDataList.push(emailValues);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//保存邮件
|
||||
const receiveEmailList = emailDataList.filter(emailRow => emailRow.status === emailConst.status.RECEIVE || emailRow.status === emailConst.status.NOONE);
|
||||
|
||||
for (const emailData of receiveEmailList) {
|
||||
|
||||
const emailRow = await orm(c).insert(email).values(emailData).returning().get();
|
||||
|
||||
//设置附件保存
|
||||
for (const attRow of attList) {
|
||||
const attValues = {...attRow};
|
||||
attValues.emailId = emailRow.emailId;
|
||||
attValues.accountId = emailRow.accountId;
|
||||
attValues.userId = emailRow.userId;
|
||||
attValues.attId = null;
|
||||
await orm(c).insert(att).values(attValues).run();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const bouncedEmail = emailDataList.find(emailRow => emailRow.status === emailConst.status.BOUNCED);
|
||||
|
||||
|
||||
let status = emailConst.status.DELIVERED;
|
||||
let message = ''
|
||||
//如果有拒收邮件,就把发件人的邮件改成拒收
|
||||
if (bouncedEmail) {
|
||||
const messageJson = { message: bouncedEmail.message };
|
||||
message = JSON.stringify(messageJson);
|
||||
status = emailConst.status.BOUNCED;
|
||||
}
|
||||
|
||||
await orm(c).update(email).set({ status: emailConst.status.DELIVERED, message: message }).where(eq(email.emailId, sendEmailData.emailId)).run();
|
||||
|
||||
},
|
||||
|
||||
imgReplace(content, cidAttList, r2domain) {
|
||||
|
||||
@@ -6,17 +6,18 @@ const resendService = {
|
||||
|
||||
async webhooks(c, body) {
|
||||
|
||||
const params = {}
|
||||
console.error(body)
|
||||
const params = {
|
||||
resendEmailId: body.data.email_id,
|
||||
status: emailConst.status.SENT
|
||||
}
|
||||
|
||||
if (body.type === 'email.delivered') {
|
||||
params.status = emailConst.status.DELIVERED
|
||||
params.resendEmailId = body.data.email_id
|
||||
params.message = null
|
||||
}
|
||||
|
||||
if (body.type === 'email.complained') {
|
||||
params.status = emailConst.status.COMPLAINED
|
||||
params.resendEmailId = body.data.email_id
|
||||
params.message = null
|
||||
}
|
||||
|
||||
@@ -24,19 +25,16 @@ const resendService = {
|
||||
let bounce = body.data.bounce
|
||||
bounce = JSON.stringify(bounce);
|
||||
params.status = emailConst.status.BOUNCED
|
||||
params.resendEmailId = body.data.email_id
|
||||
params.message = bounce
|
||||
}
|
||||
|
||||
if (body.type === 'email.delivery_delayed') {
|
||||
params.status = emailConst.status.DELAYED
|
||||
params.resendEmailId = body.data.email_id
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -174,6 +174,50 @@ const roleService = {
|
||||
|
||||
selectByName(c, roleName) {
|
||||
return orm(c).select().from(role).where(eq(role.name, roleName)).get();
|
||||
},
|
||||
|
||||
selectByUserIds(c, userIds) {
|
||||
|
||||
if (!userIds && userIds.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return orm(c).select({ ...role, userId: user.userId }).from(user).leftJoin(role, eq(role.roleId, user.type)).where(inArray(user.userId, userIds)).all();
|
||||
|
||||
},
|
||||
|
||||
isBanEmail(banEmail, fromEmail) {
|
||||
|
||||
banEmail = banEmail.split(',').filter(item => item !== '');
|
||||
|
||||
if (banEmail.includes('*')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const item of banEmail) {
|
||||
|
||||
if (verifyUtils.isDomain(item)) {
|
||||
|
||||
const banDomain = item.toLowerCase();
|
||||
const receiveDomain = emailUtils.getDomain(fromEmail.toLowerCase());
|
||||
|
||||
if (banDomain === receiveDomain) {
|
||||
return true;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (item.toLowerCase() === fromEmail.toLowerCase()) {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ const fileUtils = {
|
||||
async getBuffHash(buff) {
|
||||
const hashBuffer = await crypto.subtle.digest('SHA-256', buff);
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
||||
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
return hashArray.slice(0, 16).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
},
|
||||
|
||||
base64ToDataStr(base64) {
|
||||
|
||||
Reference in New Issue
Block a user