1 Commits
3 changed files with 85 additions and 14 deletions
+81 -10
View File
@@ -85,8 +85,64 @@ export async function submitRegistration(prevState: unknown, formData: FormData)
}; };
} }
// Hjälpfunktion för att bygga och skicka via Stalwart JMAP async function sendMailJMAP(toEmail: string, replyToEmail: string, subject: string, htmlContent: string, fromName: string, fromEmail: string) {
async function sendMailJMAP(toEmail: string, replyToEmail: string, subject: string, htmlContent: string, fromName: string) { // 1. Hämta Mapp-ID (Drafts/Utkast) och Identitets-ID från Stalwart
const setupPayload = {
using: ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail", "urn:ietf:params:jmap:submission"],
methodCalls: [
["Mailbox/query", { accountId: accountId, filter: { role: "drafts" } }, "getMailbox"],
["Identity/get", { accountId: accountId }, "getIdentity"]
]
};
const setupRes = await fetch(jmapUrl as string, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${jmapToken}` },
body: JSON.stringify(setupPayload)
});
const setupData = await setupRes.json();
const mailboxRes = setupData.methodResponses.find((r: any) => r[0] === "Mailbox/query");
const identityRes = setupData.methodResponses.find((r: any) => r[0] === "Identity/get");
let mailboxId = mailboxRes && mailboxRes[1].ids && mailboxRes[1].ids.length > 0 ? mailboxRes[1].ids[0] : null;
// ---- NY LOGIK HÄR: Hitta rätt identitet baserat på fromEmail ----
let identityId = null;
let actualFromEmail = fromEmail;
if (identityRes && identityRes[1].list) {
// Leta efter identiteten som matchar adressen vi vill skicka från
const matchedIdentity = identityRes[1].list.find((i: any) => i.email === fromEmail);
if (matchedIdentity) {
identityId = matchedIdentity.id;
} else if (identityRes[1].list.length > 0) {
// Fallback om den exakta adressen inte fanns i listan
identityId = identityRes[1].list[0].id;
actualFromEmail = identityRes[1].list[0].email;
}
}
// Om ingen mapp med rollen "drafts" finns, hämta första bästa mapp
if (!mailboxId) {
const fallbackRes = await fetch(jmapUrl as string, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${jmapToken}` },
body: JSON.stringify({
using: ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
methodCalls: [["Mailbox/query", { accountId: accountId }, "0"]]
})
});
const fallbackData = await fallbackRes.json();
mailboxId = fallbackData.methodResponses[0][1].ids[0];
}
if (!mailboxId || !identityId) {
throw new Error("Kunde inte hitta mailboxId eller identityId i Stalwart.");
}
// 2. Skapa och skicka mailet
const payload = { const payload = {
using: [ using: [
"urn:ietf:params:jmap:core", "urn:ietf:params:jmap:core",
@@ -100,7 +156,8 @@ export async function submitRegistration(prevState: unknown, formData: FormData)
accountId: accountId, accountId: accountId,
create: { create: {
"draft-1": { "draft-1": {
from: [{ email: accountId, name: fromName }], mailboxIds: { [mailboxId as string]: true },
from: [{ email: actualFromEmail, name: fromName }], // Nu använder vi rätt adress
to: [{ email: toEmail }], to: [{ email: toEmail }],
replyTo: [{ email: replyToEmail }], replyTo: [{ email: replyToEmail }],
subject: subject, subject: subject,
@@ -123,7 +180,8 @@ export async function submitRegistration(prevState: unknown, formData: FormData)
accountId: accountId, accountId: accountId,
create: { create: {
"sub-1": { "sub-1": {
emailId: "#draft-1" emailId: "#draft-1",
identityId: identityId // Nu använder vi rätt ID
} }
} }
}, },
@@ -141,11 +199,22 @@ export async function submitRegistration(prevState: unknown, formData: FormData)
body: JSON.stringify(payload) body: JSON.stringify(payload)
}); });
if (!res.ok) { const data = await res.json();
throw new Error(`JMAP API Error: ${res.status} ${res.statusText}`);
const hasErrors = data.methodResponses.some(
(response: any) =>
response[0] === "error" ||
(response[1] && response[1].notCreated)
);
if (hasErrors) {
console.error("--- JMAP METHOD ERROR ---");
console.error(JSON.stringify(data.methodResponses, null, 2));
console.error("-------------------------");
throw new Error("JMAP accepterade anropet, men vägrade skapa/skicka mailet.");
} }
return res.json(); return data;
} }
// 6. Skapa och skicka mail // 6. Skapa och skicka mail
@@ -204,21 +273,23 @@ export async function submitRegistration(prevState: unknown, formData: FormData)
</div> </div>
`; `;
// Skicka mailen parallellt för prestanda (frivilligt, men oftast bättre än sekventiellt) // Skicka mailen parallellt
await Promise.all([ await Promise.all([
sendMailJMAP( sendMailJMAP(
'beach@lerbergetsvolleyboll.se', // To 'beach@lerbergetsvolleyboll.se', // To
rawData.email, // ReplyTo rawData.email, // ReplyTo
`Anmälan: ${rawData.team}`, // Subject `Anmälan: ${rawData.team}`, // Subject
mailTillKlubbHtml, // HTML Content mailTillKlubbHtml, // HTML Content
`Beach-anmälan: ${rawData.name}` // From Name `Beach-anmälan: ${rawData.name}`,// From Name
'beach@lerbergetsvolleyboll.se' // From Email (VIKTIGT!)
), ),
sendMailJMAP( sendMailJMAP(
rawData.email, // To rawData.email, // To
'beach@lerbergetsvolleyboll.se', // ReplyTo 'beach@lerbergetsvolleyboll.se', // ReplyTo
`Vi har tagit emot din anmälan för ${rawData.team}`, // Subject `Vi har tagit emot din anmälan för ${rawData.team}`, // Subject
mailTillAnvandareHtml, // HTML Content mailTillAnvandareHtml, // HTML Content
"LVS" // From Name "LVS Beach", // From Name
'beach@lerbergetsvolleyboll.se' // From Email (VIKTIGT!)
) )
]); ]);
+1 -1
View File
@@ -29,7 +29,7 @@ export async function getConfig() {
return { return {
showBeachPromo: true, showBeachPromo: true,
beachPage: { beachPage: {
matchStart: "2026-06-13T10:00", matchStart: "2027-06-12T10:00",
isClosedOverride: false, isClosedOverride: false,
closeReason: "Det är hela 26 lag anmälda och vi kan tyvärr inte ta emot fler anmälningar.\r\n\r\nVi är glada över förväntan och bjuder in alla andra till att komma och kolla men vi har tyvärr inte kapaciteten till att ha med fler lag.", closeReason: "Det är hela 26 lag anmälda och vi kan tyvärr inte ta emot fler anmälningar.\r\n\r\nVi är glada över förväntan och bjuder in alla andra till att komma och kolla men vi har tyvärr inte kapaciteten till att ha med fler lag.",
festivalLink: "https://www.kullahalvon.com/upptacka--uppleva/kultur--noje/evenemang-pa-kullahalvon/mat---sommarfesten.html", festivalLink: "https://www.kullahalvon.com/upptacka--uppleva/kultur--noje/evenemang-pa-kullahalvon/mat---sommarfesten.html",
+3 -3
View File
@@ -2,6 +2,6 @@ TURNSTILE_SITE_KEY=1x00000000000000000000AA
TURNSTILE_SECRET=1x0000000000000000000000000000000AA TURNSTILE_SECRET=1x0000000000000000000000000000000AA
ADMIN_PASSWORD=PASSWORD ADMIN_PASSWORD=PASSWORD
SMTP_HOST=smtp.example.com STALWART_JMAP_URL=https://mail.example.com/jmap/
SMTP_USER=USER STALWART_ACCOUNT_ID=ID
SMTP_PASS=PASSWORD STALWART_API_TOKEN=API_XXXXXXXXXXXXXXXXXXXXX