feat: add auto reply (#49)

* feat: add auto reply

* feat: add auto reply

* feat: update readme

* feat: add auto reply
This commit is contained in:
Dream Hunter
2023-12-18 21:41:15 +08:00
committed by GitHub
parent af78248145
commit 95ae65dc03
14 changed files with 349 additions and 33 deletions
+31
View File
@@ -1,3 +1,6 @@
import { createMimeMessage } from "mimetext";
import { EmailMessage } from "cloudflare:email";
const PostalMime = require("postal-mime");
const simpleParser = require('mailparser').simpleParser;
global.setImmediate = (callback) => callback();
@@ -44,6 +47,34 @@ async function email(message, env, ctx) {
message.setReject(`Failed save message to ${message.to}`);
console.log(`Failed save message from ${message.from} to ${message.to}`);
}
try {
const results = await env.DB.prepare(
`SELECT * FROM auto_reply_mails where address = ? and enabled = 1`
).bind(message.to).first();
if (results && results.source_prefix && message.from.startsWith(results.source_prefix)) {
const msg = createMimeMessage();
msg.setHeader("In-Reply-To", message.headers.get("Message-ID"));
msg.setSender({
name: results.name || results.address,
addr: results.address
});
msg.setRecipient(message.from);
msg.setSubject(results.subject || "Auto-reply");
msg.addMessage({
contentType: 'text/plain',
data: results.message || "This is an auto-reply message, please reconact later."
});
const replyMessage = new EmailMessage(
message.to,
message.from,
msg.asRaw()
);
await message.reply(replyMessage);
}
} catch (error) {
console.log("reply email error", error);
}
} else {
message.setReject(`Unknown address ${message.to}`);
console.log(`Unknown address ${message.to}`);
+55 -10
View File
@@ -32,14 +32,59 @@ api.get('/api/mails', async (c) => {
})
api.get('/api/settings', async (c) => {
return c.json(c.get("jwtPayload"));
const { address } = c.get("jwtPayload")
const results = await c.env.DB.prepare(
`SELECT * FROM auto_reply_mails where address = ?`
).bind(address).first();
if (!results) {
return c.json({
auto_reply: {},
address: address
});
}
return c.json({
auto_reply: {
subject: results.subject,
message: results.message,
enabled: results.enabled == 1,
source_prefix: results.source_prefix,
name: results.name,
},
address: address
});
})
api.post('/api/settings', async (c) => {
const { address } = c.get("jwtPayload")
const { auto_reply } = await c.req.json();
const { name, subject, source_prefix, message, enabled } = auto_reply;
if ((!subject || !message) && enabled) {
return c.text("Invalid subject or message", 400)
}
else if (subject.length > 255 || message.length > 255) {
return c.text("Subject or message too long", 400)
}
const { success } = await c.env.DB.prepare(
`INSERT OR REPLACE INTO
auto_reply_mails
(name, address, source_prefix, subject, message, enabled)
VALUES
(?, ?, ?, ?, ?, ?)`
).bind(name || '', address, source_prefix || '', subject || '', message || '', enabled ? 1 : 0).run();
if (!success) {
return c.text("Failed to save settings", 500)
}
return c.json({
success: success
})
})
api.get('/open_api/settings', async (c) => {
// check header x-custom-auth
let needAuth = false;
if (c.env.PASSWORDS && c.env.PASSWORDS.length > 0) {
const auth = c.req.headers.get("x-custom-auth");
const auth = c.req.raw.headers.get("x-custom-auth");
needAuth = !c.env.PASSWORDS.includes(auth);
}
return c.json({
@@ -63,7 +108,7 @@ api.get('/api/new_address', async (c) => {
const emailAddress = c.env.PREFIX + name + "@" + domain
try {
const { success } = await c.env.DB.prepare(
`INSERT INTO address (name) VALUES (?)`
`INSERT INTO address(name) VALUES(?)`
).bind(name + "@" + domain).run();
if (!success) {
return c.text("Failed to create address", 500)
@@ -92,7 +137,7 @@ api.get('/admin/address', async (c) => {
return c.text("Invalid offset", 400)
}
const { results } = await c.env.DB.prepare(
`SELECT * FROM address order by id desc limit ? offset ?`
`SELECT * FROM address order by id desc limit ? offset ? `
).bind(limit, offset).all();
let count = 0;
if (offset == 0) {
@@ -113,7 +158,7 @@ api.get('/admin/address', async (c) => {
api.delete('/admin/delete_address/:id', async (c) => {
const { id } = c.req.param();
const { success } = await c.env.DB.prepare(
`DELETE FROM address WHERE id = ?`
`DELETE FROM address WHERE id = ? `
).bind(id).run();
if (!success) {
return c.text("Failed to delete address", 500)
@@ -126,7 +171,7 @@ api.delete('/admin/delete_address/:id', async (c) => {
api.get('/admin/show_password/:id', async (c) => {
const { id } = c.req.param();
const name = await c.env.DB.prepare(
`SELECT name FROM address WHERE id = ?`
`SELECT name FROM address WHERE id = ? `
).bind(id).first("name");
// compute address
const emailAddress = c.env.PREFIX + name
@@ -148,12 +193,12 @@ api.get('/admin/mails', async (c) => {
return c.text("Invalid offset", 400)
}
const { results } = await c.env.DB.prepare(
`SELECT id, source, subject, message FROM mails where address = ? order by id desc limit ? offset ?`
`SELECT id, source, subject, message FROM mails where address = ? order by id desc limit ? offset ? `
).bind(address, limit, offset).all();
let count = 0;
if (offset == 0) {
const { count: mailCount } = await c.env.DB.prepare(
`SELECT count(*) as count FROM mails where address = ?`
`SELECT count(*) as count FROM mails where address = ? `
).bind(address).first();
count = mailCount;
}
@@ -173,7 +218,7 @@ api.get('/admin/mails_unknow', async (c) => {
}
const { results } = await c.env.DB.prepare(`
SELECT id, source, subject, message FROM mails
where address NOT IN (select concat('${c.env.PREFIX}', name) from address)
where address NOT IN(select concat('${c.env.PREFIX}', name) from address)
order by id desc limit ? offset ? `
).bind(limit, offset).all();
let count = 0;
@@ -181,7 +226,7 @@ api.get('/admin/mails_unknow', async (c) => {
const { count: mailCount } = await c.env.DB.prepare(`
SELECT count(*) as count FROM mails
where address NOT IN
(select concat('${c.env.PREFIX}', name) from address)`
(select concat('${c.env.PREFIX}', name) from address)`
).first();
count = mailCount;
}
+2 -2
View File
@@ -10,7 +10,7 @@ app.use('/*', cors());
app.use('/api/*', async (c, next) => {
// check header x-custom-auth
if (c.env.PASSWORDS && c.env.PASSWORDS.length > 0) {
const auth = c.req.headers.get("x-custom-auth");
const auth = c.req.raw.headers.get("x-custom-auth");
if (!auth || !c.env.PASSWORDS.includes(auth)) {
return c.text("Need Password", 401)
}
@@ -25,7 +25,7 @@ app.use('/api/*', async (c, next) => {
app.use('/admin/*', async (c, next) => {
// check header x-admin-auth
if (c.env.ADMIN_PASSWORDS && c.env.ADMIN_PASSWORDS.length > 0) {
const adminAuth = c.req.headers.get("x-admin-auth");
const adminAuth = c.req.raw.headers.get("x-admin-auth");
if (adminAuth && c.env.ADMIN_PASSWORDS.includes(adminAuth)) {
await next();
return;