mailu branch failed

This commit is contained in:
2025-07-28 12:18:54 +08:00
commit 2999e562c7
19 changed files with 1178 additions and 0 deletions

12
backend/Dockerfile Normal file
View File

@@ -0,0 +1,12 @@
FROM node:20-alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5182
CMD [ "node", "app.js" ]

32
backend/app.js Normal file
View File

@@ -0,0 +1,32 @@
const express = require('express');
const cors = require('cors');
const db = require('./db');
const app = express();
const port = 5182;
app.use(cors());
app.use(express.json());
// API to get messages for a recipient
app.get('/api/messages', async (req, res) => {
const { recipient } = req.query;
if (!recipient) {
return res.status(400).send('Recipient is required');
}
try {
const [rows] = await db.execute(
'SELECT id, sender, subject, body, received_at FROM emails WHERE recipient = ? ORDER BY received_at DESC',
[recipient]
);
res.json(rows);
} catch (error) {
console.error('Failed to fetch emails:', error);
res.status(500).send('Failed to fetch emails');
}
});
app.listen(port, () => {
console.log(`Backend server listening at http://localhost:${port}`);
});

13
backend/db.js Normal file
View File

@@ -0,0 +1,13 @@
const mysql = require('mysql2');
const pool = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
module.exports = pool.promise();

18
backend/init.sql Normal file
View File

@@ -0,0 +1,18 @@
CREATE TABLE IF NOT EXISTS emails (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
recipient VARCHAR(255) NOT NULL,
sender VARCHAR(255) NOT NULL,
subject VARCHAR(512),
body TEXT,
received_at DATETIME DEFAULT CURRENT_TIMESTAMP,
raw MEDIUMBLOB
);
CREATE TABLE IF NOT EXISTS email_attachments (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
email_id BIGINT NOT NULL,
filename VARCHAR(255),
content_type VARCHAR(128),
content LONGBLOB,
FOREIGN KEY (email_id) REFERENCES emails(id) ON DELETE CASCADE
);

16
backend/package.json Normal file
View File

@@ -0,0 +1,16 @@
{
"name": "backend",
"version": "1.0.0",
"description": "Backend for email service",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "^5.1.0",
"mysql2": "^3.14.2",
"mailparser": "^3.7.4",
"cors": "^2.8.5",
"get-stream": "^9.0.1"
}
}

54
backend/saveEmail.js Normal file
View File

@@ -0,0 +1,54 @@
#!/usr/bin/env node
const { simpleParser } = require('mailparser');
const db = require('./db');
// Using require for get-stream v5 as it's CommonJS
const getStream = require('get-stream');
async function saveEmail(rawEmail) {
try {
const parsed = await simpleParser(rawEmail);
// Ensure 'to' and 'from' objects exist before accessing 'text'
const recipient = parsed.to ? parsed.to.text : 'undisclosed-recipients';
const sender = parsed.from ? parsed.from.text : 'unknown-sender';
const subject = parsed.subject;
const body = parsed.text || (parsed.html || '');
const [result] = await db.execute(
'INSERT INTO emails (recipient, sender, subject, body, raw) VALUES (?, ?, ?, ?, ?)',
[recipient, sender, subject, body, rawEmail]
);
console.log(`Email saved with ID: ${result.insertId}`);
if (parsed.attachments && parsed.attachments.length > 0) {
for (const attachment of parsed.attachments) {
await db.execute(
'INSERT INTO email_attachments (email_id, filename, content_type, content) VALUES (?, ?, ?, ?)',
[result.insertId, attachment.filename, attachment.contentType, attachment.content]
);
console.log(`Attachment ${attachment.filename} saved.`);
}
}
} catch (error) {
console.error('Failed to save email:', error);
// Exit with an error code to signal failure to the calling process (e.g., Mailu)
process.exit(1);
}
}
(async () => {
try {
const rawEmail = await getStream(process.stdin);
if (rawEmail && rawEmail.length > 0) {
await saveEmail(rawEmail);
} else {
console.log('Received empty input, no email to save.');
}
} catch (error) {
console.error('Error reading from stdin:', error);
process.exit(1);
}
})();