Stacks included:
- Infrastructure: traefik, authentik, gitea, registry, watchtower, dockge
- Monitoring: smokeping, changedetection
- Apps: ghost, gollum, wallabag, radicale, invidious, xbackbone, filebrowser, syncthing, zerotier
- Custom: obsidian-tools, memento, perilous, ramz, bookclub, brain
🤖 Generated with Claude Code
52 lines
1.3 KiB
JavaScript
52 lines
1.3 KiB
JavaScript
const express = require('express');
|
|
const nodemailer = require('nodemailer');
|
|
|
|
const app = express();
|
|
app.use(express.urlencoded({ extended: true }));
|
|
app.use(express.json());
|
|
|
|
if (process.env.TRUST_PROXY === 'true') {
|
|
app.set('trust proxy', true);
|
|
}
|
|
|
|
const transporter = nodemailer.createTransport({
|
|
host: process.env.SMTP_HOST,
|
|
port: parseInt(process.env.SMTP_PORT || '465'),
|
|
secure: process.env.SMTP_SECURE === 'true',
|
|
auth: {
|
|
user: process.env.SMTP_USER,
|
|
pass: process.env.SMTP_PASS
|
|
}
|
|
});
|
|
|
|
app.post('/submit', async (req, res) => {
|
|
const { secret, ...formData } = req.body;
|
|
|
|
if (secret !== process.env.SECRET_PHRASE) {
|
|
return res.status(403).send('Invalid secret phrase');
|
|
}
|
|
|
|
try {
|
|
await transporter.sendMail({
|
|
from: process.env.MAIL_FROM,
|
|
to: process.env.MAIL_TO,
|
|
subject: 'New Form Submission',
|
|
text: Object.entries(formData)
|
|
.map(([key, value]) => `${key}: ${value}`)
|
|
.join('\n')
|
|
});
|
|
|
|
res.redirect(process.env.THANK_YOU_URL || '/thanks.html');
|
|
} catch (error) {
|
|
console.error('Mail error:', error);
|
|
res.status(500).send('Failed to send email');
|
|
}
|
|
});
|
|
|
|
const port = parseInt(process.env.BIND_PORT || '3000');
|
|
const host = process.env.BIND_HOST || '0.0.0.0';
|
|
|
|
app.listen(port, host, () => {
|
|
console.log(`Form mailer listening on ${host}:${port}`);
|
|
});
|