← back to Norma
app/api/drafts/[id]/send-test/route.ts
111 lines
import { NextRequest, NextResponse } from 'next/server';
import { query } from '@/lib/db';
import { requireRole } from '@/lib/require-role';
import { auditLog } from '@/lib/audit';
import { getOrgId } from '@/lib/orgId';
import { htmlToText } from '@/lib/export';
import nodemailer from 'nodemailer';
type RouteContext = { params: Promise<{ id: string }> };
/**
* POST /api/drafts/[id]/send-test
* Send a test email using nodemailer + SMTP config from environment.
* Body (optional): { to?: string }
*/
export async function POST(request: NextRequest, context: RouteContext) {
const auth = requireRole(request, 'admin', 'staff');
if (auth instanceof NextResponse) return auth;
const orgId = auth.role === 'admin' ? getOrgId(request) : auth.orgId;
if (!orgId) {
return NextResponse.json({ error: 'Missing org context' }, { status: 400 });
}
const { id } = await context.params;
// Check SMTP configuration
const smtpHost = process.env.SMTP_HOST;
const smtpPort = process.env.SMTP_PORT;
const smtpUser = process.env.SMTP_USER;
const smtpPass = process.env.SMTP_PASS;
if (!smtpHost || !smtpPort || !smtpUser || !smtpPass) {
return NextResponse.json(
{
error: 'SMTP not configured. Set SMTP_HOST, SMTP_PORT, SMTP_USER, and SMTP_PASS environment variables to enable test sending.',
},
{ status: 400 }
);
}
try {
const body = await request.json().catch(() => ({}));
// Determine recipient
const recipientEmail = body.to || process.env.TEST_SEND_TO;
if (!recipientEmail) {
return NextResponse.json(
{ error: 'No recipient specified. Provide "to" in the request body or set TEST_SEND_TO environment variable.' },
{ status: 400 }
);
}
// Fetch the draft
const draftResult = await query(`SELECT * FROM drafts WHERE id = $1 AND org_id = $2`, [id, orgId]);
if (draftResult.rowCount === 0) {
return NextResponse.json({ error: 'Draft not found' }, { status: 404 });
}
const draft = draftResult.rows[0];
// Create transporter
const transporter = nodemailer.createTransport({
host: smtpHost,
port: parseInt(smtpPort, 10),
secure: parseInt(smtpPort, 10) === 465,
auth: {
user: smtpUser,
pass: smtpPass,
},
});
// Build and send the email
const plainText = draft.body_text || htmlToText(draft.body_html);
await transporter.sendMail({
from: `"${draft.from_name}" <${draft.from_email}>`,
replyTo: draft.reply_to || undefined,
to: recipientEmail,
subject: `[TEST] ${draft.subject}`,
text: plainText,
html: draft.body_html,
});
// Update draft with test send info
const now = new Date().toISOString();
await query(
`UPDATE drafts SET test_sent_at = $1, test_sent_to = $2 WHERE id = $3 AND org_id = $4`,
[now, recipientEmail, id, orgId]
);
const ip = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip') || undefined;
await auditLog(
'draft.test_sent',
'draft',
id,
{ sent_to: recipientEmail, subject: draft.subject },
ip
);
return NextResponse.json({
success: true,
sentTo: recipientEmail,
sentAt: now,
});
} catch (err) {
console.error('[api/drafts/[id]/send-test] POST error:', (err as Error).message);
return NextResponse.json({ error: 'Failed to send test email' }, { status: 500 });
}
}