@@ -10,6 +10,7 @@ import { normalizeEmail } from "../_shared/email.ts";
1010import { resolveCampaignBaseUrlFromEnv } from "../_shared/url.ts" ;
1111import { fillTemplate } from "../_shared/mailing/template.ts" ;
1212import { sendEmail , verifyTransport } from "./email.ts" ;
13+ import { buildRedirectResponse } from "../_shared/http.ts" ;
1314import {
1415 getSenderCredentialIssue ,
1516 isTokenExpired ,
@@ -375,7 +376,18 @@ function toHtmlFromText(template: string): string {
375376}
376377
377378function buildUnsubscribeUrl ( token : string ) : string {
378- return `${ PUBLIC_CAMPAIGN_BASE_URL } /functions/v1/email-campaigns/unsubscribe/${ token } ` ;
379+ const base = ( FRONTEND_HOST || PUBLIC_CAMPAIGN_BASE_URL ) . replace ( / \/ $ / , "" ) ;
380+ return `${ base } /u/${ token } ` ;
381+ }
382+
383+ function buildOpenTrackingUrl ( token : string ) : string {
384+ const base = ( FRONTEND_HOST || PUBLIC_CAMPAIGN_BASE_URL ) . replace ( / \/ $ / , "" ) ;
385+ return `${ base } /o/${ token } ` ;
386+ }
387+
388+ function buildClickTrackingUrl ( token : string ) : string {
389+ const base = ( FRONTEND_HOST || PUBLIC_CAMPAIGN_BASE_URL ) . replace ( / \/ $ / , "" ) ;
390+ return `${ base } /c/${ token } ` ;
379391}
380392
381393async function triggerCampaignProcessorFromEdge ( ) {
@@ -1041,7 +1053,7 @@ async function injectTrackers(
10411053 recipientId ,
10421054 originalUrl ,
10431055 ) ;
1044- const trackedUrl = ` ${ PUBLIC_CAMPAIGN_BASE_URL } /functions/v1/email-campaigns/track/click/ ${ token } ` ;
1056+ const trackedUrl = buildClickTrackingUrl ( token ) ;
10451057
10461058 // Replace both quoted-printable encoded (href=3D"...") and regular (href="...")
10471059 updatedHtml = updatedHtml . replace (
@@ -1055,7 +1067,7 @@ async function injectTrackers(
10551067 }
10561068
10571069 if ( trackOpen ) {
1058- const pixelUrl = ` ${ PUBLIC_CAMPAIGN_BASE_URL } /functions/v1/email-campaigns/track/open/ ${ openToken } ` ;
1070+ const pixelUrl = buildOpenTrackingUrl ( openToken ) ;
10591071 updatedHtml += `<img src="${ pixelUrl } " alt="" width="1" height="1" style="display:none" />` ;
10601072 }
10611073
@@ -2039,13 +2051,9 @@ app.get("/unsubscribe/:token", async (c: Context) => {
20392051 const supabaseAdmin = createSupabaseAdmin ( ) ;
20402052
20412053 if ( token === "preview-unsubscribe" ) {
2042- return new Response ( null , {
2043- status : 302 ,
2044- headers : {
2045- ...corsHeaders ,
2046- Location : `${ FRONTEND_HOST } /unsubscribe/success?preview=true` ,
2047- } ,
2048- } ) ;
2054+ return buildRedirectResponse (
2055+ `${ FRONTEND_HOST } /unsubscribe/success?preview=true` ,
2056+ ) ;
20492057 }
20502058
20512059 const { data : recipient , error } = await supabaseAdmin
@@ -2056,13 +2064,7 @@ app.get("/unsubscribe/:token", async (c: Context) => {
20562064 . single ( ) ;
20572065
20582066 if ( error || ! recipient ) {
2059- return new Response ( null , {
2060- status : 302 ,
2061- headers : {
2062- ...corsHeaders ,
2063- Location : `${ FRONTEND_HOST } /unsubscribe/failure` ,
2064- } ,
2065- } ) ;
2067+ return buildRedirectResponse ( `${ FRONTEND_HOST } /unsubscribe/failure` ) ;
20662068 }
20672069
20682070 await supabaseAdmin
@@ -2110,13 +2112,7 @@ app.get("/unsubscribe/:token", async (c: Context) => {
21102112 ) } `
21112113 : `${ FRONTEND_HOST } /unsubscribe/success` ;
21122114
2113- return new Response ( null , {
2114- status : 302 ,
2115- headers : {
2116- ...corsHeaders ,
2117- Location : successUrl ,
2118- } ,
2119- } ) ;
2115+ return buildRedirectResponse ( successUrl ) ;
21202116} ) ;
21212117
21222118app . get ( "/track/open/:token" , async ( c : Context ) => {
@@ -2174,7 +2170,7 @@ app.get("/track/click/:token", async (c: Context) => {
21742170 url : link . url ,
21752171 } ) ;
21762172
2177- return c . redirect ( link . url , 302 ) ;
2173+ return buildRedirectResponse ( link . url ) ;
21782174} ) ;
21792175
21802176app . post ( "/email-sending-request" , authMiddleware , async ( c : Context ) => {
0 commit comments