@@ -10,12 +10,26 @@ export const dynamic = 'force-dynamic'
1010const logger = createLogger ( 'MailSendAPI' )
1111
1212const MailSendSchema = z . object ( {
13- fromAddress : z . string ( ) . email ( 'Invalid from email address' ) . min ( 1 , 'From address is required' ) ,
14- to : z . string ( ) . email ( 'Invalid email address' ) . min ( 1 , 'To email is required' ) ,
13+ fromAddress : z . string ( ) . min ( 1 , 'From address is required' ) ,
14+ to : z . string ( ) . min ( 1 , 'To email is required' ) ,
1515 subject : z . string ( ) . min ( 1 , 'Subject is required' ) ,
1616 body : z . string ( ) . min ( 1 , 'Email body is required' ) ,
1717 contentType : z . enum ( [ 'text' , 'html' ] ) . optional ( ) . nullable ( ) ,
1818 resendApiKey : z . string ( ) . min ( 1 , 'Resend API key is required' ) ,
19+ cc : z
20+ . union ( [ z . string ( ) . email ( ) , z . array ( z . string ( ) . email ( ) ) ] )
21+ . optional ( )
22+ . nullable ( ) ,
23+ bcc : z
24+ . union ( [ z . string ( ) . email ( ) , z . array ( z . string ( ) . email ( ) ) ] )
25+ . optional ( )
26+ . nullable ( ) ,
27+ replyTo : z
28+ . union ( [ z . string ( ) . email ( ) , z . array ( z . string ( ) . email ( ) ) ] )
29+ . optional ( )
30+ . nullable ( ) ,
31+ scheduledAt : z . string ( ) . datetime ( ) . optional ( ) . nullable ( ) ,
32+ tags : z . string ( ) . optional ( ) . nullable ( ) ,
1933} )
2034
2135export async function POST ( request : NextRequest ) {
@@ -52,23 +66,50 @@ export async function POST(request: NextRequest) {
5266 const resend = new Resend ( validatedData . resendApiKey )
5367
5468 const contentType = validatedData . contentType || 'text'
55- const emailData =
56- contentType === 'html'
57- ? {
58- from : validatedData . fromAddress ,
59- to : validatedData . to ,
60- subject : validatedData . subject ,
61- html : validatedData . body ,
62- text : validatedData . body . replace ( / < [ ^ > ] * > / g, '' ) , // Strip HTML for text version
63- }
64- : {
65- from : validatedData . fromAddress ,
66- to : validatedData . to ,
67- subject : validatedData . subject ,
68- text : validatedData . body ,
69- }
70-
71- const { data, error } = await resend . emails . send ( emailData )
69+ const emailData : Record < string , unknown > = {
70+ from : validatedData . fromAddress ,
71+ to : validatedData . to ,
72+ subject : validatedData . subject ,
73+ }
74+
75+ if ( contentType === 'html' ) {
76+ emailData . html = validatedData . body
77+ emailData . text = validatedData . body . replace ( / < [ ^ > ] * > / g, '' )
78+ } else {
79+ emailData . text = validatedData . body
80+ }
81+
82+ if ( validatedData . cc ) {
83+ emailData . cc = validatedData . cc
84+ }
85+
86+ if ( validatedData . bcc ) {
87+ emailData . bcc = validatedData . bcc
88+ }
89+
90+ if ( validatedData . replyTo ) {
91+ emailData . replyTo = validatedData . replyTo
92+ }
93+
94+ if ( validatedData . scheduledAt ) {
95+ emailData . scheduledAt = validatedData . scheduledAt
96+ }
97+
98+ if ( validatedData . tags ) {
99+ const tagPairs = validatedData . tags . split ( ',' ) . map ( ( pair ) => {
100+ const trimmed = pair . trim ( )
101+ if ( ! trimmed . includes ( ':' ) ) return null
102+ const [ name , value ] = trimmed . split ( ':' )
103+ return { name : name ?. trim ( ) || '' , value : value ?. trim ( ) || '' }
104+ } )
105+ emailData . tags = tagPairs . filter (
106+ ( tag ) : tag is { name : string ; value : string } => tag !== null && ! ! tag . name
107+ )
108+ }
109+
110+ const { data, error } = await resend . emails . send (
111+ emailData as unknown as Parameters < typeof resend . emails . send > [ 0 ]
112+ )
72113
73114 if ( error ) {
74115 logger . error ( `[${ requestId } ] Email sending failed:` , error )
0 commit comments