import logging from '../../lib/logging.js'; import { developer_admin, API } from '../../lib/api.js'; import { company } from '../../emails/config.js'; import { get_config, dns_check, send_email, load_templates } from '../../lib/email.js'; const log = logging.create(import.meta.url); const ERRORS = { ip4_double_reverse: { id: 0, title: "No IP4 Double Reverse", active: false, text: "IPv4 addresses need to have both a reverse DNS record and a matching DNS record for the host. You have to add a reverse DNS for the IP Host address and then make sure that exact IPv4 address is listed in your DNS with a A record." }, ip6_double_reverse: { id: 1, title: "No IP6 Double Reverse", active: false, text: "IPv6 addresses need to have both a reverse DNS record and a matching DNS record for the host. You have to add a reverse DNS for the IP Host address and then make sure that exact IPv6 address is listed in your DNS with a AAAA record (not A)." }, no_mx_record: { id: 2, title: "No MX Record", active: false, text: "You can run your server without an MX record but it makes it less reliable. Add a single record with your main hostname and a 10 Priority." }, spf_invalid: { id: 3, title: "SPF Record Invalid", active: false, text: "Your SPF record needs to mention both the IPv4 address with ip4:X and IPv6 address with ip6:X." }, no_dmarc: { id: 4, title: "No DMARC Record", active: false, text: "You need a DMARC record, and it's recommended you configure it to p=none but route the errors to an email address on this server so you can monitor failures." }, no_ip4_address: { id: 5, title: "No IP4 Address", active: false, text: "Most email providers are now requiring an IPv4 address that is also double reverse lookup, which means you need an IPv4 A record and a reverse DNS for it that exactly matches." }, no_ip6_address: { id: 6, title: "No IP6 Address", active: false, text: "Most email providers are now requiring an IPv6 address that is also double reverse lookup, which means you need an IPv6 AAAA record and a reverse DNS for it that exactly matches." }, no_spf: { id: 7, title: "No SPF Record", active: false, text: "You need an SPF record. It should be a TXT record and list your IP4 and IP6 addresses in the format \"v=spf1 a mx ip4:X ip6:Y ~all\"." }, } const analyze_dns = (dns) => { let r = []; // consider using a Rools engine if this gets too insane if(dns.ip4.error) { r.push(ERRORS.no_ip4_address); r.push(ERRORS.ip4_double_reverse); } if(dns.ip4.reverse_errors) { r.push(ERRORS.ip4_double_reverse); } if(dns.ip6.error) { r.push(ERRORS.no_ip6_address); r.push(ERRORS.ip6_double_reverse); } if(dns.ip6.reverse_errors) { r.push(ERRORS.ip6_double_reverse); } if(dns.mx_error) { r.push(ERRORS.no_mx_record); } if(dns.spf_error) { r.push(ERRORS.no_spf); } if(dns.dmarc_error) { r.push(ERRORS.no_dmarc); } if(r.length > 1) r[0].active = true; return r; } export const get = async (req, res) => { const api = new API(req, res); const rules = { domain_name: "required"} const form = api.validate(rules); if(!api.admin_authenticated) { return api.error(401, "Admin rights required."); } try { if(form._valid) { const dns = await dns_check(form.domain_name); const tests = analyze_dns(dns); log.debug(dns); return api.reply(200, {dns, tests}); } else { return api.validation_error(res, form); } } catch (error) { log.error(error); return api.error(500, "Internal Server Error"); } } get.authenticated = !developer_admin; const send_test = async (email) => { try { const test_email = await load_templates("test"); const text = test_email.txt(email); const html = test_email.html(email); return send_email({ from: company.mail, to: email, subject: `Test email for ${company.website}`, text, html }); } catch(error) { log.error(error); return error; } } export const post = async (req, res) => { const rules = { to_address: "required|email" } const api = new API(req, res); if(!api.admin_authenticated) { return api.error(401, "Admin rights required."); } try { const form = api.validate(rules); if(form._valid) { log.debug(`Sending test email to ${form.to_address}`); const error = await send_test(form.to_address); return api.reply(200, { message: "Email sent. Check server logs.", error: error === undefined ? error : error.message, config: get_config() }); } else { return api.validation_error(res, form); } } catch (error) { log.error(error); return api.error(500, "Internal Server Error"); } } post.authenticated = !developer_admin;