1+ import { EmailTemplate } from '../../../components/EmailTemplate' ;
2+ import { Resend } from 'resend' ;
3+
4+ // Validate RESEND_API_KEY is configured
5+ const apiKey = process . env . RESEND_API_KEY ;
6+ if ( ! apiKey || apiKey . trim ( ) . length === 0 ) {
7+ throw new Error (
8+ 'RESEND_API_KEY is not configured. Please set the RESEND_API_KEY environment variable.'
9+ ) ;
10+ }
11+
12+ const resend = new Resend ( apiKey ) ;
13+
14+ function isNonEmptyString ( value : unknown ) : value is string {
15+ return typeof value === 'string' && value . trim ( ) . length > 0 ;
16+ }
17+
18+ function isValidEmail ( value : unknown ) : value is string {
19+ if ( typeof value !== 'string' ) return false ;
20+ const email = value . trim ( ) ;
21+ // Basic email pattern; not exhaustive but sufficient for simple validation
22+ const emailRegex = / ^ [ ^ \s @ ] + @ [ ^ \s @ ] + \. [ ^ \s @ ] + $ / ;
23+ return email . length > 0 && emailRegex . test ( email ) ;
24+ }
25+
26+ export async function POST ( req : Request ) {
27+ try {
28+ // Get the form data from the request
29+ const body = await req . json ( ) ;
30+
31+ if ( ! body || typeof body !== 'object' ) {
32+ return Response . json (
33+ { error : 'Invalid request body; expected JSON object.' } ,
34+ { status : 400 } ,
35+ ) ;
36+ }
37+
38+ const {
39+ name,
40+ emailAddress,
41+ subject,
42+ message,
43+ } = body as {
44+ name ?: unknown ;
45+ emailAddress ?: unknown ;
46+ subject ?: unknown ;
47+ message ?: unknown ;
48+ } ;
49+
50+ if ( ! isNonEmptyString ( name ) ) {
51+ return Response . json (
52+ { error : 'Field "name" is required and must be a non-empty string.' } ,
53+ { status : 400 } ,
54+ ) ;
55+ }
56+
57+ if ( ! isValidEmail ( emailAddress ) ) {
58+ return Response . json (
59+ { error : 'Field "emailAddress" is required and must be a valid email address.' } ,
60+ { status : 400 } ,
61+ ) ;
62+ }
63+
64+ if ( ! isNonEmptyString ( message ) ) {
65+ return Response . json (
66+ { error : 'Field "message" is required and must be a non-empty string.' } ,
67+ { status : 400 } ,
68+ ) ;
69+ }
70+
71+ const normalizedSubject =
72+ typeof subject === 'string' && subject . trim ( ) . length > 0
73+ ? subject
74+ : 'New Message from Monash Coding Site' ;
75+
76+ const { data, error } = await resend . emails . send ( {
77+ from : 'noreply@monashcoding.com' ,
78+ // to: 'coding@monashclubs.org',
79+ to : 'projects@monashcoding.com' ,
80+ replyTo : ( emailAddress as string ) . trim ( ) , // User's email will be set as reply-to
81+ subject : normalizedSubject ,
82+ react : EmailTemplate ( {
83+ name : ( name as string ) . trim ( ) ,
84+ emailAddress : ( emailAddress as string ) . trim ( ) ,
85+ subject : normalizedSubject ,
86+ message : ( message as string ) . trim ( ) ,
87+ } ) ,
88+ } ) ;
89+
90+ if ( error ) {
91+ console . error ( 'Resend API error:' , error ) ;
92+ return Response . json ( { error } , { status : 500 } ) ;
93+ }
94+
95+ return Response . json ( data ) ;
96+ } catch ( error ) {
97+ console . error ( 'Catch error:' , error ) ;
98+ return Response . json ( { error : String ( error ) } , { status : 500 } ) ;
99+ }
100+ }
0 commit comments