@@ -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 ( ) . min ( 1 ) , z . array ( z . string ( ) . min ( 1 ) ) ] )
21+ . optional ( )
22+ . nullable ( ) ,
23+ bcc : z
24+ . union ( [ z . string ( ) . min ( 1 ) , z . array ( z . string ( ) . min ( 1 ) ) ] )
25+ . optional ( )
26+ . nullable ( ) ,
27+ replyTo : z
28+ . union ( [ z . string ( ) . min ( 1 ) , z . array ( z . string ( ) . min ( 1 ) ) ] )
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,52 @@ 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+ const colonIndex = trimmed . indexOf ( ':' )
102+ if ( colonIndex === - 1 ) return null
103+ const name = trimmed . substring ( 0 , colonIndex ) . trim ( )
104+ const value = trimmed . substring ( colonIndex + 1 ) . trim ( )
105+ return { name, value : value || '' }
106+ } )
107+ emailData . tags = tagPairs . filter (
108+ ( tag ) : tag is { name : string ; value : string } => tag !== null && ! ! tag . name
109+ )
110+ }
111+
112+ const { data, error } = await resend . emails . send (
113+ emailData as unknown as Parameters < typeof resend . emails . send > [ 0 ]
114+ )
72115
73116 if ( error ) {
74117 logger . error ( `[${ requestId } ] Email sending failed:` , error )
0 commit comments