1import{m as ye,u as re,j as e,P as ee,D as ke,h as z,R as le,O as _,E as V,r as T,s as L,t as O,v as K,w as v,B as C,S as se,K as we,b as E,ap as ae,C as $,c as R,d as A,e as M,f as D,ab as ne,I as ie,T as X,p as y,g as q,aY as Se,a7 as de,an as Ce}from"./index-ePDyumzS.js";import{b,h as ce,p as _e,i as oe,X as xe,Y as me,T as he,A as Q,o as $e,L as J}from"./recharts-qOI1PvBd.js";import{T as B,a as F,b as S,c as d,d as U,e as i}from"./table-DDz2MWrs.js";import{C as k}from"./charts-CjoS4r8i.js";import{f as j,g as w,a as Y}from"./format-CRKJO8mk.js";import{u as P}from"./use-async-UEQ1rRDQ.js";import{R as Re}from"./refresh-cw-KA_lVuNl.js";import{M as Ae}from"./mail-CO0cvbYh.js";import{S as Me}from"./send-DsXzg3zt.js";import{S as ue}from"./search-zXrr4T7T.js";import{T as pe}from"./trash-2-BEYhy3KJ.js";import{C as De}from"./circle-x-B5UWGLSb.js";import{C as Te}from"./circle-check-CArcdmO1.js";import{C as Le}from"./chevron-right-BDkXrM51.js";/** 2 * @license lucide-react v0.462.0 - ISC 3 * 4 * This source code is licensed under the ISC license. 5 * See the LICENSE file in the root directory of this source tree. 6 */const je=ye("CircleSlash",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"9",x2:"15",y1:"15",y2:"9",key:"1dfufj"}]]),ge={login_link:"Sign-in links",signup_link:"Signup confirmations",invitation:"Team invitations",lead_alert:"Lead alerts",digest:"Digest briefings",digest_test:"Digest tests",health_alert:"Assistant health alerts",anomaly_alert:"Anomaly alerts",deliverability_alert:"Delivery alerts",delivery_test:"Delivery tests",mailgun_test:"Mailgun diagnostics",ticket:"Support tickets",ticket_update:"Ticket updates",email_answer:"Email channel answers",email_draft:"Email channel drafts",platform:"Platform notices",email:"Uncategorised"},G=s=>ge[s]??s.replace(/_/g," "),Oe=[{value:"all",label:"Any outcome"},{value:"delivered",label:"Delivered"},{value:"opened",label:"Opened"},{value:"pending",label:"No outcome yet"},{value:"bounced",label:"Bounced"},{value:"failed",label:"Failed"},{value:"complained",label:"Marked as spam"}],fe={borderRadius:8,borderColor:k.grid,fontSize:12},H=s=>s==null?"â":`${s}%`;function os(){const{user:s}=re();return s!=null&&s.platformAdmin?e.jsx(Ke,{}):e.jsxs(e.Fragment,{children:[e.jsx(ee,{title:"Email delivery",description:"Whether the mail this platform sends actually arrives."}),e.jsx(ke,{required:"admin"})]})}function Ke(){const[s,a]=b.useState(30),[n,c]=b.useState(""),[g,o]=b.useState(!1),{data:l,loading:x,error:N,reload:p}=P(()=>z(`/platform-email?days=${s}${n?`&domain=${encodeURIComponent(n)}`:""}`),[s,n]),m=b.useCallback(async()=>{o(!0);try{const t=await le("/platform-email/sync"),r=t.results.filter(f=>f.error);r.length?_.error(`${r[0].domain}: ${r[0].error}`):_.success(`Refreshed ${t.results.reduce((f,I)=>f+I.days,0)} days from Mailgun`),p()}catch(t){_.error((t==null?void 0:t.message)??"Sync failed")}finally{o(!1)}},[p]);if(N)return e.jsxs(e.Fragment,{children:[e.jsx(ee,{title:"Email delivery"}),e.jsx(V,{message:N,onRetry:p})]});const h=l==null?void 0:l.summary;return e.jsxs(e.Fragment,{children:[e.jsx(ee,{title:"Email delivery",description:"Every mail the platform sends, what the receiving servers did with it, and the health of the sending domains.",actions:e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[((l==null?void 0:l.domains.length)??0)>1&&e.jsxs(T,{value:n||"all",onValueChange:t=>c(t==="all"?"":t),children:[e.jsx(L,{className:"h-8 w-[210px] text-xs",children:e.jsx(O,{})}),e.jsxs(K,{children:[e.jsx(v,{value:"all",children:"All sending domains"}),l==null?void 0:l.domains.map(t=>e.jsx(v,{value:t,children:t},t))]})]}),e.jsxs(T,{value:String(s),onValueChange:t=>a(Number(t)),children:[e.jsx(L,{className:"h-8 w-[130px] text-xs",children:e.jsx(O,{})}),e.jsx(K,{children:[7,30,90,365].map(t=>e.jsxs(v,{value:String(t),children:["Last ",t," days"]},t))})]}),e.jsxs(C,{variant:"outline",size:"sm",onClick:m,disabled:g,children:[e.jsx(Re,{className:g?"animate-spin":""})," Sync Mailgun"]}),e.jsx(Xe,{})]})}),l&&(!l.configured||!l.webhookKeySet)&&e.jsx(Ie,{data:l}),x||!l||!h?e.jsxs(e.Fragment,{children:[e.jsx(se,{className:"h-16 w-full"}),e.jsx("div",{className:"mt-4 grid grid-cols-2 gap-4 md:grid-cols-3 xl:grid-cols-6",children:e.jsx(we,{c
6ount:6})}),e.jsx(se,{className:"mt-6 h-64 w-full"})]}):e.jsxs(e.Fragment,{children:[e.jsx(Ee,{status:h.status,message:h.message}),e.jsxs("div",{className:"mt-4 grid grid-cols-2 gap-4 md:grid-cols-3 xl:grid-cols-6",children:[e.jsx(E,{label:"Delivery rate",value:H(h.deliveryRate),sub:`${j(h.delivered)} of ${j(h.accepted)}`}),e.jsx(E,{label:"Bounce rate",value:H(h.bounceRate),sub:`${j(h.bounced)} hard bounces`}),e.jsx(E,{label:"Complaint rate",value:H(h.complaintRate),sub:`${j(h.complained)} marked as spam`}),e.jsx(E,{label:"Open rate",value:H(h.openRate),sub:`${j(h.opened)} opened`}),e.jsx(E,{label:"Accepted",value:j(h.accepted),sub:`in ${s} days`,icon:e.jsx(Ae,{})}),e.jsx(E,{label:"No outcome yet",value:j(h.loggedNoOutcome),sub:`of ${j(h.logged)} logged sends`,icon:h.loggedNoOutcome>0?e.jsx(ae,{}):void 0})]}),e.jsx(Be,{domains:l.domains}),e.jsxs("div",{className:"mt-6 grid gap-6 xl:grid-cols-2",children:[e.jsx(Fe,{stats:l.stats}),e.jsx(Ue,{stats:l.stats})]}),e.jsx(ze,{auth:l.auth,clickTracking:l.clickTracking}),l.byKind.length>0&&e.jsx(Pe,{rows:l.byKind}),e.jsx(We,{days:s}),e.jsx(Ge,{days:s}),e.jsx(Ye,{domains:l.domains})]})]})}function Ie({data:s}){return e.jsxs($,{className:"border-amber-300/70 bg-amber-50/70 dark:border-amber-500/30 dark:bg-amber-500/10",children:[e.jsxs(R,{className:"pb-3",children:[e.jsxs(A,{className:"flex items-center gap-2 text-base",children:[e.jsx(ae,{className:"h-4 w-4 text-amber-600"})," Delivery tracking is not fully wired up"]}),e.jsx(M,{children:"Sends are logged either way, but without the webhook below nothing can say whether they arrived."})]}),e.jsxs(D,{className:"space-y-3 text-sm",children:[!s.configured&&e.jsxs("p",{className:"text-muted-foreground",children:["Mailgun itself is not configured: set ",e.jsx("code",{className:"rounded bg-card px-1 font-mono text-xs",children:"MAILGUN_API_KEY"})," and"," ",e.jsx("code",{className:"rounded bg-card px-1 font-mono text-xs",children:"MAILGUN_DOMAIN"}),". Until then no mail is sent at all."]}),!s.webhookKeySet&&e.jsxs("p",{className:"text-muted-foreground",children:["No webhook signing key:",e.jsxs("span",{className:"mt-1 flex w-fit items-center gap-1",children:[e.jsx("code",{className:"rounded bg-card px-2 py-1 font-mono text-xs",children:"npx wrangler secret put MAILGUN_WEBHOOK_KEY"}),e.jsx(ne,{text:"npx wrangler secret put MAILGUN_WEBHOOK_KEY",label:"",className:"px-2"})]})]}),e.jsxs("div",{children:[e.jsxs("p",{className:"text-muted-foreground",children:["In Mailgun open ",e.jsx("span",{className:"font-medium text-foreground",children:"Send â Webhooks"})," and add this URL for"," ",e.jsx("span",{className:"font-medium text-foreground",children:"Delivered"}),", ",e.jsx("span",{className:"font-medium text-foreground",children:"Permanent Fail"}),","," ",e.jsx("span",{className:"font-medium text-foreground",children:"Temporary Fail"}),", ",e.jsx("span",{className:"font-medium text-foreground",children:"Complained"}),","," ",e.jsx("span",{className:"font-medium text-foreground",children:"Unsubscribed"})," and ",e.jsx("span",{className:"font-medium text-foreground",children:"Opened"}),":"]}),e.jsxs("span",{className:"mt-1 flex w-fit items-center gap-1",children:[e.jsx("code",{className:"rounded bg-card px-2 py-1 font-mono text-xs",children:s.webhookUrl}),e.jsx(ne,{text:s.webhookUrl,label:"",className:"px-2"})]})]})]})]})}function Ee({status:s,message:a}){const n={green:{cls:"border-emerald-300 bg-emerald-50 text-emerald-900 dark:border-emerald-900 dark:bg-emerald-950/40 dark:text-emerald-200",icon:e.jsx(Te,{className:"h-5 w-5"}),label:"Healthy"},yellow:{cls:"border-amber-300 bg-amber-50 text-amber-900 dark:border-amber-900 dark:bg-amber-950/40 dark:text-amber-200",icon:e.jsx(ae,{className:"h-5 w-5"}),label:"Needs attention"},red:{cls:"border-red-300 bg-red-50 text-red-900 dark:border-red-900 dark:bg-red-950/40 dark:text-red-200",icon:e.jsx(De,{className:"h-5 w-5"}),label:"Failing"}}[s];return e.jsxs("div",{className:`flex items-start gap-3 rounded-lg border px-4 py-3 ${n.cls}`,children:[e.jsx("div",{className:"mt-0.5 shrink-0",children:n.icon}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-semibold",children:n.label}),e.jsx("div",{className:"text-sm opacity-90",children:a})]})]})}function Be({domains:s}){const[a,n]=b.useState(""),[c,g]=b.useState(""),[o,l]=b.useState(""),{data:x,loading:N,error:p,reload:m}=P(()=>c?z(`/platform-email/trace?email=${encodeURIComponent(c)}`):Promise.resolve(null),[c]);async function h(r,f,I){l(`${r}:${f}`);try{await de(`/platform-email/suppressions?domain=${encodeURIComponent(r)}&type=${f}&address=${encodeURIComponent(I)}`),_.success(`${I} removed from ${f} on ${r}`),m()}catch(W){_.error((W==null?void 0:W.message)??"Could not remove the suppression")}finally{l("")}}const t=((x==null?void 0:x.suppressions)??[]).filter(r=>r.entries.length>0);return e.jsxs($,{className:"mt-6",children:[e.jsxs(R,{className:"pb-3",children:[e.jsxs(A,{className:"flex items-center gap-2 text-base",children:[e.jsx(ue,{className:"h-4 w-4 text-gold-dark"})," Look up a recipient"]}),e.jsx(M,{children:"Everything sent to one address, what came back, and whether Mailgun is currently refusing to send there at all."})]}),e.jsxs(D,{className:"space-y-4",children:[e.jsxs("form",{className:"flex flex-wrap gap-2",onSubmit:r=>{r.preventDefault(),g(a.trim().toLowerCase())},children:[e.jsx(ie,{value:a,onChange:r=>n(r.target.value),placeholder:"[email protected]",className:"h-9 max-w-sm",type:"email"}),e.jsx(C,{type:"submit",variant:"gold",size:"sm",disabled:!a.includes("@"),children:"Trace"}),c&&e.jsx(C,{type:"button",variant:"ghost",size:"sm",onClick:()=>{g(""),n("")},children:"Clear"})]}),p&&e.jsx(V,{message:p,onRetry:m}),c&&N&&e.jsx(X,{rows:3}),x&&!N&&e.jsxs("div",{className:"space-y-4",children:[e.jsx("div",{className:`rounded-md border px-3 py-2 text-sm ${t.length?"border-red-300 bg-red-50 text-red-900 dark:border-red-900 dark:bg-red-950/40 dark:text-red-200":"border-border bg-muted/40"}`,children:x.verdict}),t.length>0&&e.jsx("div",{className:"space-y-2",children:t.map(r=>r.entries.map(f=>e.jsxs("div",{className:"flex flex-wrap items-center gap-3 rounded-md border px-3 py-2 text-sm",children:[e.jsx(je,{className:"h-4 w-4 shrink-0 text-red-600"}),e.jsxs("span",{children:[e.jsx("span",{className:"font-medium",children:f.type})," on ",e.jsx("code",{className:"font-mono text-xs",children:r.domain})]}),f.code&&e.jsx(y,{variant:"outline",children:f.code}),e.jsx("span",{className:"min-w-0 flex-1 truncate text-muted-foreground",children:f.reason??"no reason recorded"}),f.createdAt&&e.jsx("span",{className:"text-xs text-muted-foreground",children:w(f.createdAt)}),e.jsxs(C,{variant:"outline",size:"sm",disabled:o===`${r.domain}:${f.type}`,onClick:()=>h(r.domain,f.type,x.address),children:[e.jsx(pe,{})," Remove"]})]},`${r.domain}:${f.type}`)))}),s.length>0&&t.length===0&&e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Not on any suppression list for ",s.join(", "),"."]}),x.sends.length===0?e.jsx(q,{title:"No sends on record",description:"Nothing has been sent to this address since delivery logging started."}):e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(B,{children:[e.jsx(F,{children:e.jsxs(S,{children:[e.jsx(d,{children:"Sent"}),e.jsx(d,{children:"Kind"}),e.jsx(d,{children:"Subject"}),e.jsx(d,{children:"Outcome"}),e.jsx(d,{children:"Reason"})]})}),e.jsx(U,{children:x.sends.map(r=>e.jsxs(S,{children:[e.jsx(i,{className:"whitespace-nowrap tabular-nums",children:w(r.created_at)}),e.jsx(i,{className:"whitespace-nowrap",children:G(r.kind)}),e.jsx(i,{className:"max-w-[280px] truncate text-muted-foreground",children:r.subject??"â"}),e.jsx(i,{children:e.jsx(Ne,{row:r})}),e.jsx(i,{className:"max-w-[320px] text-xs text-muted-foreground",children:r.last_reason??r.error??"â"})]},r.id))})]})}),x.events.length>0&&e.jsxs("div",{className:"overflow-x-auto",children:[e.jsx("div",{className:"mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground",children:"What the receiving servers said"}),e.jsxs(B,{children:[e.jsx(F,{children:e.jsxs(S,{children:[e.jsx(d,{children:"When"}),e.jsx(d,{children:"Event"}),e.jsx(d,{children:"Code"}),e.jsx(d,{children:"Response"}),e.jsx(d,{children:"MX host"})]})}),e.jsx(U,{children:x.events.map(r=>e.jsxs(S,{children:[e.jsx(i,{className:"whitespace-nowrap tabular-nums",children:w(r.occurred_at)}),e.jsx(i,{children:e.jsx(te,{event:r.event,severity:r.severity})}),e.jsx(i,{className:"tabular-nums",children:r.code??"â"}),e.jsx(i,{className:"max-w-[420px] text-xs text-muted-foreground",children:r.smtp_response??r.reason??"â"}),e.jsx(i,{className:"text-xs text-muted-foreground",children:r.mx_host??"â"})]},r.id))})]})]})]})]})]})}function Fe({stats:s}){return e.jsxs($,{children:[e.jsxs(R,{className:"pb-3",children:[e.jsx(A,{className:"text-base",children:"Volume per day"}),e.jsx(M,{children:"Mailgun's own totals: what it accepted from us, and what it managed to deliver."})]}),e.jsxs(D,{children:[e.jsx("div",{className:"h-56",children:s.length===0?e.jsx("p",{className:"pt-16 text-center text-sm text-muted-foreground",children:"No statistics yet. Use âSync Mailgunâ to pull history."}):e.jsx(ce,{width:"100%",height:"100%",children:e.jsxs(_e,{data:s,margin:{top:8,right:8,bottom:0,left:0},children:[e.jsx("defs",{children:e.jsxs("linearGradient",{id:"mailAccepted",x1:"0",y1:"0",x2:"0",y2:"1",children:[e.jsx("stop",{offset:"0%",stopColor:k.blue,stopOpacity:.25}),e.jsx("stop",{offset:"100%",stopColor:k.blue,stopOpacity:.02})]})}),e.jsx(oe,{stroke:k.grid,vertical:!1}),e.jsx(xe,{dataKey:"day",tickFormatter:a=>
6Y(String(a)),fontSize:11,tickLine:!1,axisLine:!1}),e.jsx(me,{fontSize:11,tickLine:!1,axisLine:!1,tickFormatter:a=>j(Number(a)),width:48}),e.jsx(he,{labelFormatter:a=>Y(String(a)),formatter:(a,n)=>[j(Number(a)),be[String(n)]??String(n)],contentStyle:fe}),e.jsx(Q,{type:"monotone",dataKey:"accepted",stroke:k.blue,strokeWidth:2,fill:"url(#mailAccepted)"}),e.jsx(Q,{type:"monotone",dataKey:"delivered",stroke:k.green,strokeWidth:2,fill:"transparent"}),e.jsx(Q,{type:"monotone",dataKey:"permFailed",stroke:"#dc2626",strokeWidth:1.5,fill:"transparent"})]})})}),e.jsx(ve,{items:[{color:k.blue,label:"Accepted"},{color:k.green,label:"Delivered"},{color:"#dc2626",label:"Hard bounces"}]})]})]})}const be={accepted:"Accepted",delivered:"Delivered",permFailed:"Hard bounces",tempFailed:"Retrying",deliveryRate:"Delivery rate",bounceRate:"Bounce rate",openRate:"Open rate"};function Ue({stats:s}){return e.jsxs($,{children:[e.jsxs(R,{className:"pb-3",children:[e.jsx(A,{className:"text-base",children:"Rates per day"}),e.jsx(M,{children:"A delivery rate sliding away from 100% is the earliest sign a provider has started refusing us."})]}),e.jsxs(D,{children:[e.jsx("div",{className:"h-56",children:s.length===0?e.jsx("p",{className:"pt-16 text-center text-sm text-muted-foreground",children:"No statistics yet."}):e.jsx(ce,{width:"100%",height:"100%",children:e.jsxs($e,{data:s,margin:{top:8,right:8,bottom:0,left:0},children:[e.jsx(oe,{stroke:k.grid,vertical:!1}),e.jsx(xe,{dataKey:"day",tickFormatter:a=>Y(String(a)),fontSize:11,tickLine:!1,axisLine:!1}),e.jsx(me,{fontSize:11,tickLine:!1,axisLine:!1,domain:[0,100],tickFormatter:a=>`${a}%`,width:44}),e.jsx(he,{labelFormatter:a=>Y(String(a)),formatter:(a,n)=>[a===null?"â":`${a}%`,be[String(n)]??String(n)],contentStyle:fe}),e.jsx(J,{type:"monotone",dataKey:"deliveryRate",stroke:k.green,strokeWidth:2,dot:!1,connectNulls:!0}),e.jsx(J,{type:"monotone",dataKey:"openRate",stroke:k.blueSoft,strokeWidth:1.5,dot:!1,connectNulls:!0}),e.jsx(J,{type:"monotone",dataKey:"bounceRate",stroke:"#dc2626",strokeWidth:1.5,dot:!1,connectNulls:!0})]})})}),e.jsx(ve,{items:[{color:k.green,label:"Delivery"},{color:k.blueSoft,label:"Opens"},{color:"#dc2626",label:"Bounces"}]})]})]})}function ve({items:s}){return e.jsx("div",{className:"mt-2 flex flex-wrap gap-4",children:s.map(a=>e.jsxs("span",{className:"flex items-center gap-1.5 text-xs text-muted-foreground",children:[e.jsx("span",{className:"h-2 w-2 rounded-full",style:{background:a.color}})," ",a.label]},a.label))})}function Z({label:s,ok:a}){return a===null?e.jsxs(y,{variant:"secondary",children:[s,": unknown"]}):e.jsxs(y,{variant:a?"success":"destructive",children:[s,": ",a?"valid":"invalid"]})}function ze({auth:s,clickTracking:a}){return e.jsxs($,{className:"mt-6",children:[e.jsxs(R,{className:"pb-3",children:[e.jsxs(A,{className:"flex items-center gap-2 text-base",children:[e.jsx(Se,{className:"h-4 w-4 text-gold-dark"})," Sending domains"]}),e.jsx(M,{children:"SPF, DKIM and DMARC decide whether a provider trusts our mail. Mail that fails these is usually discarded in silence rather than bounced, so it looks delivered here and never appears for the recipient."})]}),e.jsxs(D,{className:"space-y-4 text-sm",children:[s.length===0&&e.jsx("p",{className:"text-muted-foreground",children:"No sending domain configured."}),s.map(n=>e.jsxs("div",{className:"rounded-md border p-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("code",{className:"font-mono text-xs font-semibold",children:n.domain}),e.jsx(y,{variant:n.state==="active"?"success":n.state==="unknown"?"secondary":"warning",children:n.state}),e.jsx(Z,{label:"SPF",ok:n.spfOk}),e.jsx(Z,{label:"DKIM",ok:n.dkimOk}),n.dmarc.found?e.jsxs(y,{variant:n.dmarc.policy==="none"?"warning":"success",children:["DMARC: p=",n.dmarc.policy??"?"]}):e.jsx(y,{variant:"warning",children:"DMARC: not published"}),e.jsx(Z,{label:"Tracking CNAME",ok:n.trackingOk})]}),n.error&&e.jsx("p",{className:"mt-2 text-xs text-red-600",children:n.error}),n.dmarc.record&&e.jsx("p",{className:"mt-2 break-all font-mono text-[11px] text-muted-foreground",children:n.dmarc.record}
6),n.pending.length>0&&e.jsxs("div",{className:"mt-2",children:[e.jsx("div",{className:"text-xs font-medium text-amber-700 dark:text-amber-400",children:"DNS records Mailgun cannot verify yet"}),e.jsx("ul",{className:"mt-1 space-y-1",children:n.pending.map((c,g)=>e.jsxs("li",{className:"break-all font-mono text-[11px] text-muted-foreground",children:[c.type," ",c.name," â ",c.value]},g))})]})]},n.domain)),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Click tracking is ",a?"on":"off",". It rewrites every link through the tracking host above, so it stays off until that CNAME is verified: a rewritten sign-in link that does not resolve is worse than a missing click statistic. Set"," ",e.jsx("code",{className:"rounded bg-muted px-1 font-mono",children:"MAILGUN_CLICK_TRACKING=true"})," to enable it."]})]})]})}function Pe({rows:s}){return e.jsxs($,{className:"mt-6",children:[e.jsxs(R,{className:"pb-3",children:[e.jsx(A,{className:"text-base",children:"By kind of mail"}),e.jsx(M,{children:"A platform-wide delivery rate hides the case that matters: sign-in links failing while digests are fine."})]}),e.jsx(D,{className:"p-0",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(B,{children:[e.jsx(F,{children:e.jsxs(S,{children:[e.jsx(d,{children:"Kind"}),e.jsx(d,{className:"text-right",children:"Sent"}),e.jsx(d,{className:"text-right",children:"Delivered"}),e.jsx(d,{className:"text-right",children:"Delivery"}),e.jsx(d,{className:"text-right",children:"Opened"}),e.jsx(d,{className:"text-right",children:"Bounced"}),e.jsx(d,{className:"text-right",children:"Spam"}),e.jsx(d,{className:"text-right",children:"Send failed"}),e.jsx(d,{className:"text-right",children:"No outcome"})]})}),e.jsx(U,{children:s.map(a=>e.jsxs(S,{children:[e.jsx(i,{className:"whitespace-nowrap font-medium",children:G(a.kind)}),e.jsx(i,{className:"text-right tabular-nums",children:j(a.sent)}),e.jsx(i,{className:"text-right tabular-nums",children:j(a.delivered)}),e.jsx(i,{className:"text-right tabular-nums",children:H(a.deliveryRate)}),e.jsx(i,{className:"text-right tabular-nums",children:j(a.opened)}),e.jsx(i,{className:`text-right tabular-nums ${a.bounced?"font-medium text-red-600":""}`,children:j(a.bounced)}),e.jsx(i,{className:`text-right tabular-nums ${a.complained?"font-medium text-red-600":""}`,children:j(a.complained)}),e.jsx(i,{className:`text-right tabular-nums ${a.failedSend?"font-medium text-red-600":""}`,children:j(a.failedSend)}),e.jsx(i,{className:`text-right tabular-nums ${a.pending?"text-amber-600":""}`,children:j(a.pending)})]},a.kind))})]})})})]})}function We({days:s}){const[a,n]=b.useState("all"),[c,g]=b.useState("all"),[o,l]=b.useState(""),[x,N]=b.useState(""),[p,m]=b.useState(0),h=50,{data:t,loading:r,error:f,reload:I}=P(()=>z(`/platform-email/log?days=${s}&kind=${a}&outcome=${c}&page=${p}&pageSize=${h}`+(x?`&search=${encodeURIComponent(x)}`:"")),[s,a,c,x,p]),W=Object.keys(ge);return e.jsxs($,{className:"mt-6",children:[e.jsxs(R,{className:"pb-3",children:[e.jsx(A,{className:"text-base",children:"Message log"}),e.jsx(M,{children:"Every send, with what came back about it. Expand a row for Mailgun's own event history."})]}),e.jsxs(D,{className:"space-y-3",children:[e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsxs("form",{className:"flex gap-2",onSubmit:u=>{u.preventDefault(),m(0),N(o.trim())},children:[e.jsx(ie,{value:o,onChange:u=>l(u.target.value),placeholder:"recipient or subject",className:"h-8 w-56 text-xs"}),e.jsx(C,{type:"submit",variant:"outline",size:"sm",children:e.jsx(ue,{})})]}),e.jsxs(T,{value:a,onValueChange:u=>{m(0),n(u)},children:[e.jsx(L,{className:"h-8 w-[200px] text-xs",children:e.jsx(O,{})}),e.jsxs(K,{children:[e.jsx(v,{value:"all",children:"All kinds"}),W.map(u=>e.jsx(v,{value:u,children:G(u)},u))]})]}),e.jsxs(T,{value:c,onValueChange:u=>{m(0),g(u)},children:[e.jsx(L,{className:"h-8 w-[170px] text-xs",children:e.jsx(O,{})}),e.jsx(K,{children:Oe.map(u=>e.jsx(v,{value:u.value,children:u.label},u.value))})]})]}),f&&e.jsx(V,{message:f,onRetry:I}),r&&e.jsx(X,{rows:6}),t&&!r&&t.rows.length===0&&e.jsx(q,{title:"Nothing matches",description:"No sends in this window match the current filters."}),t&&!r&&t.rows.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(B,{children:[e.jsx(F,{children:e.jsxs(S,{children:[e.jsx(d,{className:"w-8"}),e.jsx(d,{children:"Sent"}),e.jsx(d,{children:"Recipient"}),e.jsx(d,{children:"Kind"}),e.jsx(d,{children:"Subject"}),e.jsx(d,{children:"Outcome"}),e.jsx(d,{children:"Reason"})]})}),e.jsx(U,{children:t.rows.map(u=>e.jsx(He,{row:u},u.id))})]})}),e.jsxs("div",{className:"flex items-center justify-between text-xs text-muted-foreground",children:[e.jsxs("span",{children:[j(p*h+1),"â",j(Math.min((p+1)*h,t.total))," of ",j(t.total)]}),e.jsxs("span",{className:"flex gap-2",children:[e.jsx(C,{variant:"outline",size:"sm",disabled:p===0,onClick:()=>m(u=>Math.max(0,u-1)),children:"Previous"}),e.jsx(C,{variant:"outline",size:"sm",disabled:(p+1)*h>=t.total,onClick:()=>m(u=>u+1),children:"Next"})]})]})]})]})]})}function He({row:s}){const[a,n]=b.useState(!1);return e.jsxs(e.Fragment,{children:[e.jsxs(S,{className:"cursor-pointer",onClick:()=>n(c=>!c),children:[e.jsx(i,{className:"align-top text-muted-foreground",children:a?e.jsx(Ce,{className:"h-4 w-4"}):e.jsx(Le,{className:"h-4 w-4"})}),e.jsx(i,{className:"whitespace-nowrap align-top tabular-nums",children:w(s.created_at)}),e.jsx(i,{className:"max-w-[220px] truncate align-top",children:s.recipient}),e.jsx(i,{className:"whitespace-nowrap align-top",children:G(s.kind)}),e.jsx(i,{className:"max-w-[260px] truncate align-top text-muted-foreground",children:s.subject??"â"}),e.jsx(i,{className:"align-top",children:e.jsx(Ne,{row:s})}),e.jsx(i,{className:"max-w-[280px] align-top text-xs text-muted-foreground",children:s.last_reason??s.error??"â"})]}),a&&e.jsx(S,{children:e.jsx(i,{colSpan:7,className:"bg-muted/30",children:e.jsx(Ve,{row:s})})})]})}function Ve({row:s}){const{data:a,loading:n,error:c}=P(()=>z(`/platform-email/message/${s.id}`),[s.id]),g=[["Sending domain",s.domain??"â"],["Organization",s.org_id],["Triggered by",s.actor??"system"],["Message-ID",s.message_id??"â"],["Delivered",s.delivered_at?w(s.delivered_at):"â"],["Opened",s.opened_at?`${w(s.opened_at)} (${s.open_count}Ã)`:"â"],["Clicked",s.clicked_at?`${w(s.clicked_at)} (${s.click_count}Ã)`:"â"],["Bounced",s.bounced_at?w(s.bounced_at):"â"],["Marked as spam",s.complained_at?w(s.complained_at):"â"],["Unsubscribed",s.unsubscribed_at?w(s.unsubscribed_at):"â"]];return e.jsxs("div",{className:"space-y-3 py-2",children:[e.jsx("dl",{className:"grid gap-x-6 gap-y-1 text-xs sm:grid-cols-2 lg:grid-cols-3",children:g.map(([o,l])=>e.jsxs("div",{className:"flex gap-2",children:[e.jsx("dt",{className:"shrink-0 text-muted-foreground",children:o}),e.jsx("dd",{className:"min-w-0 break-all font-medium",children:l})]},o))}),e.jsxs("div",{children:[e.jsx("div",{className:"mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground",children:"Mailgun event history"}),n&&e.jsx(se,{className:"h-16 w-full"}),c&&e.jsx("p",{className:"text-xs text-red-600",children:c}),(a==null?void 0:a.error)&&e.jsx("p",{className:"text-xs text-muted-foreground",children:a.error}),a&&!a.error&&a.events.length===0&&e.jsx("p",{className:"text-xs text-muted-foreground",children:"Mailgun has no stored events for this message. Its event retention is limited."}),a&&a.events.length>0&&e.jsx("ul",{className:"space-y-1",children:a.events.map((o,l)=>{var x,N,p,m,h;return e.jsxs("li",{className:"flex flex-wrap items-baseline gap-2 text-xs",children:[e.jsx("span",{className:"tabular-nums text-muted-foreground",children:w(new Date((o.timestamp??0)*1e3).toISOString())}),e.jsx(te,{event:String(o.event??""),severity:o.severity??null}),e.jsx("span",{className:"text-muted-foreground",children:((x=o["delivery-status"])==null?void 0:x.description)||((N=o["delivery-status"])==null?void 0:N.message)||((p=o.reject)==null?void 0:p.description)||o.reason||((m=o["client-info"])!=null&&m["client-name"]?`${o["client-info"]["client-name"]} on ${o["client-info"]["device-type"]??"?"}`:"")}),((h=o["delivery-status"])==null?void 0:h["mx-host"])&&e.jsx("span",{className:"font-mono text-[11px] text-muted-foreground",children:o["delivery-status"]["mx-host"]})]},l)})})]})]})}function Ge({days:s}){const[a,n]=b.useState("problems"),[c,g]=b.useState(0),o=50,{data:l,loading:x,error:N,reload:p}=P(()=>z(`/platform-email/events?days=${s}&event=${a}&page=${c}&pageSize=${o}`),[s,a,c]);return e.jsxs($,{className:"mt-6",children:[e.jsxs(R,{className:"pb-3",children:[e.jsxs(A,{className:"flex flex-wrap items-center justify-between gap-2 text-base",children:["Delivery events",e.jsxs(T,{value:a,onValueChange:m=>{g(0),n(m)},children:[e.jsx(L,{className:"h-8 w-[190px] text-xs",children:e.jsx(O,{})}),e.jsxs(K,{children:[e.jsx(v,{value:"problems",children:"Problems only"}),e.jsx(v,{value:"all",children:"All events"}),e.jsx(v,{value:"delivered",children:"Delivered"}),e.jsx(v,{value:"opened",children:"Opened"}),e.jsx(v,{value:"bounced",children:"Bounced"}),e.jsx(v,{value:"failed",children:"Retrying"}),e.jsx(v,{value:"complained",children:"Marked as spam"}),e.jsx(v,{value:"unsubscribed",children:"Unsubscribed"})]})]})]}),e.jsx(M,{children:"Verbatim from the receiving side, which is where the real reason for a missing mail is written."})]}),e.jsxs(D,{className:"space-y-3",children:[N&&e.jsx(V,{message:N,onRetry:p}),x&&e.jsx(X,{rows:6}),l&&!x&&l.rows.length===0&&e.jsx(q,{title:"No events",description:"Nothing has come back from Mailgun in this window for the selected filter."}),l&&!x&&l.rows.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(B,{children:[e.jsx(F,{children:e.jsxs(S,{children:[e.jsx(d,{children:"When"}),e.jsx(d,{children:"Event"}),e.jsx(d,{children:"Recipient"}),e.jsx(d,{children:"Kind"}),e.jsx(d,{children:"Code"}),e.jsx(d,{children:"What the server said"}),e.jsx(d,{children:"MX host"})]})}),e.jsx(U,{children:l.rows.map(m=>e.jsxs(S,{children:[e.jsx(i,{className:"whitespace-nowrap tabular-nums",children:w(m.occurred_at)}),e.jsx(i,{children:e.jsx(te,{event:m.event,severity:m.severity})}),e.jsx(i,{className:"max-w-[200px] truncate",children:m.recipient}),e.jsx(i,{className:"whitespace-nowrap text-muted-foreground",children:m.kind?G(m.kind):"â"}),e.jsx(i,{className:"tabular-nums",children:m.code??"â"}),e.jsx(i,{className:"max-w-[360px] text-xs text-muted-foreground",children:m.smtp_response??m.reason??"â"}),e.jsx(i,{className:"max-w-[180px] truncate font-mono text-[11px] text-muted-foreground",children:m.mx_host??"â"})]},m.id))})]})}),e.jsxs("div",{className:"flex items-center justify-between text-xs text-muted-foreground",children:[e.jsxs("span",{children:[j(l.total)," events"]}),e.jsxs("span",{className:"flex gap-2",children:[e.jsx(C,{variant:"outline",size:"sm",disabled:c===0,onClick:()=>g(m=>Math.max(0,m-1)),children:"Previous"}),e.jsx(C,{variant:"outline",size:"sm",disabled:(c+1)*o>=l.total,onClick:()=>g(m=>m+1),children:"Next"})]})]})]})]})]})}function Ye({domains:s}){const[a,n]=b.useState(s[0]??""),[c,g]=b.useState("bounces"),[o,l]=b.useState(""),{data:x,loading:N,error:p,reload:m}=P(()=>a?z(`/platform-email/suppressions?domain=${encodeURIComponent(a)}&type=${c}`):Promise.resolve({domain:"",items:[]}),[a,c]);async function h(t){l(t);try{await de(`/platform-email/suppressions?domain=${encodeURIComponent(a)}&type=${c}&address=${encodeURIComponent(t)}`),_.success(`${t} can receive mail again`),m()}catch(r){_.error((r==null?void 0:r.message)??"Could not remove the suppression")}finally{l("")}}return e.jsxs($,{className:"mt-6",children:[e.jsxs(R,{className:"pb-3",children:[e.jsxs(A,{className:"flex flex-wrap items-center justify-between gap-2 text-base",children:[e.jsxs("span",{className:"flex items-center gap-2",children:[e.jsx(je,{className:"h-4 w-4 text-gold-dark"})," Suppression lists"]}),e.jsxs("span",{className:"flex gap-2",children:[s.length>1&&e.jsxs(T,{value:a,onValueChange:n,children:[e.jsx(L,{className:"h-8 w-[210px] text-xs",children:e.jsx(O,{})}),e.jsx(K,{children:s.map(t=>e.jsx(v,{value:t,children:t},t))})]}),e.jsxs(T,{value:c,onValueChange:t=>g(t),children:[e.jsx(L,{className:"h-8 w-[150px] text-xs",children:e.jsx(O,{})}),e.jsxs(K,{children:[e.jsx(v,{value:"bounces",children:"Bounces"}),e.jsx(v,{value:"complaints",children:"Complaints"}),e.jsx(v,{value:"unsubscribes",children:"Unsubscribes"})]})]})]})]}),e.jsx(M,{children:"Mailgun drops mail to a suppressed address before it leaves, and it stays suppressed forever. One old bounce is enough to make every future sign-in link disappear, which is why removal lives here."})]}),e.jsxs(D,{className:"space-y-3",children:[p&&e.jsx(V,{message:p,onRetry:m}),(x==null?void 0:x.error)&&e.jsx("p",{className:"text-sm text-amber-700 dark:text-amber-400",children:x.error}),N&&e.jsx(X,{rows:4}),x&&!N&&!x.error&&x.items.length===0&&e.jsx(q,{title:"Nothing suppressed",description:`No ${c} recorded for ${a}.`}),x&&!N&&x.items.length>0&&e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(B,{children:[e.jsx(F,{children:e.jsxs(S,{children:[e.jsx(d,{children:"Address"}),e.jsx(d,{children:"Code"}),e.jsx(d,{children:"Reason"}),e.jsx(d,{children:"Since"}),e.jsx(d,{className:"w-24"})]})}),e.jsx(U,{children:x.items.map(t=>e.jsxs(S,{children:[e.jsx(i,{children:t.address}),e.jsx(i,{className:"tabular-nums",children:t.code??"â"}),e.jsx(i,{className:"max-w-[420px] text-xs text-muted-foreground",children:t.error??t.reason??"â"}),e.jsx(i,{className:"whitespace-nowrap tabular-nums",children:t.created_at?w(t.created_at):"â"}),e.jsx(i,{children:e.jsxs(C,{variant:"outline",size:"sm",disabled:o===t.address,onClick:()=>h(t.address),children:[e.jsx(pe,{})," Remove"]})})]},t.address))})]})})]})]})}function Xe(){const{user:s}=re(),[a,n]=b.useState(!1);async function c(){const g=window.prompt("Send a delivery test to:",(s==null?void 0:s.email)??"");if(g){n(!0);try{const o=await le("/platform-email/test",{to:g});o.ok?_.success(`Test sent to ${o.to} â it will appear in the log below`):_.error("Mailgun refused the test send. Check the log for the error.")}catch(o){_.error((o==null?void 0:o.message)??"Test send failed")}finally{n(!1)}}}return e.jsxs(C,{variant:"outline",size:"sm",onClick:c,disabled:a,children:[e.jsx(Me,{})," Send test"]})}function Ne({row:s}){return s.status==="failed"?e.jsx(y,{variant:"destructive",children:"never sent"}):s.status==="skipped"?e.jsx(y,{variant:"secondary",children:"not sent"}):e.jsxs("span",{className:"flex flex-wrap gap-1",children:[s.bounced_at&&e.jsx(y,{variant:"destructive",children:"bounced"}),s.complained_at&&e.jsx(y,{variant:"destructive",children:"spam"}),s.unsubscribed_at&&e.jsx(y,{variant:"warning",children:"unsubscribed"}),s.delivered_at&&e.jsx(y,{variant:"success",children:"delivered"}),s.opened_at&&e.jsx(y,{variant:"gold",children:"opened"}),s.clicked_at&&e.jsx(y,{variant:"gold",children:"clicked"}),!s.delivered_at&&!s.bounced_at&&!s.failed_at&&e.jsx(y,{variant:"secondary",children:"no outcome"}),s.failed_at&&!s.delivered_at&&!s.bounced_at&&e.jsx(y,{variant:"warning",children:"retrying"})]})}function te({event:s,severity:a}){const n=s==="delivered"?"success":s==="bounced"||s==="rejected"||s==="complained"?"destructive":s==="failed"||s==="unsubscribed"?"warning":s==="opened"||s==="clicked"?"gold":"secondary",c=s==="failed"&&a==="temporary"?"retrying":s;return e.jsx(y,{variant:n,children:c})}export{os as PlatformEmailPage};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.