Plesk-Sync: Legacy-Mailgroup-Adressen synchronisierten nicht
Prod-Bug: zusätzliche Weiterleitung eintragen → Toast meldet Erfolg, Plesk übernimmt nichts. Plesk hat zwei unabhängige Verteil-Mechanismen, Mailgroup (alte CLI-Anlagen) und Forwarding (neue). Unser Sync schrieb nur in Forwarding, die alte Adresse lief aber via Mailgroup → set:-Befehle landeten in ungenutzter Tabelle. Stage funktionierte, weil dort frisch im Forwarding- Modus angelegt. - EmailExistsResult um mailgroupActive/Members + forwardingActive/ Targets erweitert. - pleskProvider.emailExists parst alle vier Felder aus --info- stdout (Mailgroup: true|false, Group member(s): ..., Forward request: ...). - pleskProvider.updateForwardTargets setzt -mailgroup false dazu – deaktiviert den Legacy-Mechanismus. - syncForwardingForEmail holt vorm Plesk-Update die bestehenden Mailgroup-Members und Forwarding-Targets ab und importiert sie in unsere additionalForwardingEmails-Liste (canonical-Key-Dedup). Verlustfrei – kein Empfänger fällt beim Umschalten raus. Smoke-Test mit echtem Plesk-stdout (User-Log): 3 Group-Members sauber geparst, leeres "Forward request" als [] erkannt.
This commit is contained in:
@@ -180,17 +180,56 @@ export class PleskEmailProvider implements IEmailProvider {
|
|||||||
|
|
||||||
// Mailbox-Status aus stdout parsen (Format: "Mailbox: true" oder "Mailbox: false")
|
// Mailbox-Status aus stdout parsen (Format: "Mailbox: true" oder "Mailbox: false")
|
||||||
let hasMailbox: boolean | undefined;
|
let hasMailbox: boolean | undefined;
|
||||||
|
let mailgroupActive: boolean | undefined;
|
||||||
|
let mailgroupMembers: string[] | undefined;
|
||||||
|
let forwardingActive: boolean | undefined;
|
||||||
|
let forwardingTargets: string[] | undefined;
|
||||||
if (exists && result.stdout) {
|
if (exists && result.stdout) {
|
||||||
const mailboxMatch = result.stdout.match(/Mailbox:\s*(true|false)/i);
|
const mailboxMatch = result.stdout.match(/Mailbox:\s*(true|false)/i);
|
||||||
if (mailboxMatch) {
|
if (mailboxMatch) {
|
||||||
hasMailbox = mailboxMatch[1].toLowerCase() === 'true';
|
hasMailbox = mailboxMatch[1].toLowerCase() === 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mailgroup-Status + Mitglieder. Plesk listet sie auf einer
|
||||||
|
// Zeile, Adressen sind durch Whitespace getrennt.
|
||||||
|
const mailgroupMatch = result.stdout.match(/Mailgroup:\s*(true|false)/i);
|
||||||
|
if (mailgroupMatch) {
|
||||||
|
mailgroupActive = mailgroupMatch[1].toLowerCase() === 'true';
|
||||||
|
}
|
||||||
|
const groupMembersMatch = result.stdout.match(/Group member\(s\):\s*([^\n]*)/i);
|
||||||
|
if (groupMembersMatch) {
|
||||||
|
mailgroupMembers = groupMembersMatch[1]
|
||||||
|
.trim()
|
||||||
|
.split(/\s+/)
|
||||||
|
.filter((m) => m.includes('@'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forwarding-Status + Ziele. Plesk druckt "Forward request: <addrs>".
|
||||||
|
// Auf manchen Plesk-Versionen heißt das Feld auch "Forwarding".
|
||||||
|
const forwardActiveMatch = result.stdout.match(/Forwarding:\s*(true|false)/i);
|
||||||
|
if (forwardActiveMatch) {
|
||||||
|
forwardingActive = forwardActiveMatch[1].toLowerCase() === 'true';
|
||||||
|
}
|
||||||
|
const forwardTargetsMatch = result.stdout.match(/Forward(?:ing)?(?: request)?:\s*([^\n]*)/i);
|
||||||
|
if (forwardTargetsMatch) {
|
||||||
|
forwardingTargets = forwardTargetsMatch[1]
|
||||||
|
.trim()
|
||||||
|
.split(/\s+/)
|
||||||
|
.filter((m) => m.includes('@'));
|
||||||
|
if (forwardingActive === undefined) {
|
||||||
|
forwardingActive = (forwardingTargets?.length ?? 0) > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
exists,
|
exists,
|
||||||
email: exists ? email : undefined,
|
email: exists ? email : undefined,
|
||||||
hasMailbox,
|
hasMailbox,
|
||||||
|
mailgroupActive,
|
||||||
|
mailgroupMembers,
|
||||||
|
forwardingActive,
|
||||||
|
forwardingTargets,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// HTTP-Fehler oder Netzwerkfehler
|
// HTTP-Fehler oder Netzwerkfehler
|
||||||
@@ -458,11 +497,20 @@ export class PleskEmailProvider implements IEmailProvider {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plesk CLI API: Weiterleitungsziele aktualisieren
|
// Plesk CLI API: Weiterleitungsziele aktualisieren.
|
||||||
// Format für -forwarding-addresses: "set:email1,email2" ersetzt alle Adressen
|
// Format für -forwarding-addresses: "set:email1,email2" ersetzt alle Adressen.
|
||||||
|
//
|
||||||
|
// WICHTIG: Mailgroup parallel deaktivieren. Plesk hat zwei
|
||||||
|
// unabhängige Verteil-Mechanismen (Mailgroup vs. Forwarding).
|
||||||
|
// Alt-Anlagen liefen oft via Mailgroup – unser `set:`-Befehl auf
|
||||||
|
// forwarding-addresses ändert dann eine ungenutzte Tabelle und
|
||||||
|
// Mails landen weiterhin bei den Mailgroup-Members.
|
||||||
|
// Der Service-Layer importiert vorher die Mailgroup-Members in die
|
||||||
|
// `targets`-Liste, damit beim Umschalten nichts verloren geht.
|
||||||
await this.request('POST', '/api/v2/cli/mail/call', {
|
await this.request('POST', '/api/v2/cli/mail/call', {
|
||||||
params: [
|
params: [
|
||||||
'--update', email,
|
'--update', email,
|
||||||
|
'-mailgroup', 'false',
|
||||||
'-forwarding', 'true',
|
'-forwarding', 'true',
|
||||||
'-forwarding-addresses', `set:${targets.join(',')}`,
|
'-forwarding-addresses', `set:${targets.join(',')}`,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -42,6 +42,14 @@ export interface EmailExistsResult {
|
|||||||
exists: boolean;
|
exists: boolean;
|
||||||
email?: string;
|
email?: string;
|
||||||
hasMailbox?: boolean; // true wenn echte Mailbox vorhanden
|
hasMailbox?: boolean; // true wenn echte Mailbox vorhanden
|
||||||
|
// Plesk hat zwei unabhängige Verteil-Mechanismen, beide können parallel
|
||||||
|
// aktiv sein. Manuelle/Legacy-Anlagen nutzen oft "Mailgroup" statt
|
||||||
|
// "Forwarding" – unser Sync muss alte Mitglieder dort einsammeln,
|
||||||
|
// sonst gehen sie beim Umschalten auf Forwarding verloren.
|
||||||
|
mailgroupActive?: boolean;
|
||||||
|
mailgroupMembers?: string[];
|
||||||
|
forwardingActive?: boolean;
|
||||||
|
forwardingTargets?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EmailOperationResult {
|
export interface EmailOperationResult {
|
||||||
|
|||||||
@@ -558,7 +558,50 @@ export async function syncForwardingForEmail(
|
|||||||
|
|
||||||
const localPart = stressfreiEmail.email.split('@')[0];
|
const localPart = stressfreiEmail.email.split('@')[0];
|
||||||
|
|
||||||
// 1) Forwards neu setzen.
|
// 0) Auto-Migration: Plesk hat zwei Verteil-Mechanismen (Mailgroup +
|
||||||
|
// Forwarding). Alt-Anlagen liefen oft via Mailgroup – unser Sync
|
||||||
|
// schreibt aber nur in die Forwarding-Liste, daher landeten neue
|
||||||
|
// Adressen nirgendwo. Hier holen wir die aktuellen Mailgroup-Members
|
||||||
|
// ab und ziehen alle, die wir nicht schon kennen, in unsere
|
||||||
|
// additionalForwardingEmails-Liste rein. Der nachfolgende Plesk-Call
|
||||||
|
// deaktiviert dann die Mailgroup und schreibt die volle Liste als
|
||||||
|
// Forwarding. Verlustfrei – kein Empfänger fällt raus.
|
||||||
|
try {
|
||||||
|
const pleskState = await checkEmailExists(localPart);
|
||||||
|
const existingMembers = [
|
||||||
|
...(pleskState.mailgroupMembers ?? []),
|
||||||
|
...(pleskState.forwardingTargets ?? []),
|
||||||
|
];
|
||||||
|
const newImports: string[] = [];
|
||||||
|
for (const member of existingMembers) {
|
||||||
|
const key = canonicalEmailKey(member);
|
||||||
|
if (!seenKeys.has(key)) {
|
||||||
|
seenKeys.add(key);
|
||||||
|
forwardTargets.push(member);
|
||||||
|
newImports.push(member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newImports.length > 0) {
|
||||||
|
const mergedAdditional = [
|
||||||
|
...parseAdditionalForwards(stressfreiEmail.additionalForwardingEmails),
|
||||||
|
...newImports,
|
||||||
|
];
|
||||||
|
await prisma.stressfreiEmail.update({
|
||||||
|
where: { id },
|
||||||
|
data: { additionalForwardingEmails: serializeAdditionalForwards(mergedAdditional) },
|
||||||
|
});
|
||||||
|
console.log(
|
||||||
|
`[syncForwardingForEmail] Importiert aus Plesk-Mailgroup für ${stressfreiEmail.email}:`,
|
||||||
|
newImports,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (importErr) {
|
||||||
|
// Nicht hart fehlschlagen – im schlimmsten Fall fehlen ein paar
|
||||||
|
// alte Empfänger, aber der eigentliche Sync soll trotzdem laufen.
|
||||||
|
console.error('[syncForwardingForEmail] Mailgroup-Import fehlgeschlagen:', importErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1) Forwards neu setzen (deaktiviert intern Mailgroup).
|
||||||
const forwardResult = await setEmailForwardTargets(localPart, forwardTargets);
|
const forwardResult = await setEmailForwardTargets(localPart, forwardTargets);
|
||||||
if (!forwardResult.success) {
|
if (!forwardResult.success) {
|
||||||
// Wenn Plesk meldet „nicht gefunden", liefern wir eine sprechende Meldung
|
// Wenn Plesk meldet „nicht gefunden", liefern wir eine sprechende Meldung
|
||||||
|
|||||||
@@ -97,6 +97,30 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
|
|||||||
|
|
||||||
## ✅ Erledigt
|
## ✅ Erledigt
|
||||||
|
|
||||||
|
- [x] **🐞 Plesk-Sync: Legacy-Mailgroup-Adressen synchronisierten nicht**
|
||||||
|
- Prod-Bug: User trägt zusätzliche Weiterleitung ein, Toast meldet
|
||||||
|
Erfolg, aber Plesk übernimmt nichts. Ursache: Plesk hat zwei
|
||||||
|
Verteil-Mechanismen, **Mailgroup** (alte CLI-Anlagen,
|
||||||
|
`Group member(s):`) und **Forwarding** (`Forward request:`). Unser
|
||||||
|
Sync schrieb nur in Forwarding, die Adresse lief aber via Mailgroup
|
||||||
|
→ unsere `set:`-Befehle landeten in einer ungenutzten Tabelle.
|
||||||
|
Stage funktionierte, weil dort die Adressen frisch vom CRM angelegt
|
||||||
|
wurden (Forwarding-Modus von Anfang an).
|
||||||
|
- `EmailExistsResult` um `mailgroupActive` + `mailgroupMembers` +
|
||||||
|
`forwardingActive` + `forwardingTargets` erweitert.
|
||||||
|
- `pleskProvider.emailExists` parst alle vier Felder aus dem
|
||||||
|
`--info`-stdout (`Mailgroup: true|false`, `Group member(s): ...`,
|
||||||
|
`Forward request: ...`).
|
||||||
|
- `pleskProvider.updateForwardTargets` setzt jetzt zusätzlich
|
||||||
|
`-mailgroup false`, damit der Legacy-Mechanismus deaktiviert wird
|
||||||
|
und nur noch Forwarding aktiv ist.
|
||||||
|
- `syncForwardingForEmail`: vor dem Plesk-Update werden bestehende
|
||||||
|
Mailgroup-Members + Forwarding-Targets abgeholt und in unsere
|
||||||
|
`additionalForwardingEmails`-Liste **importiert** (canonical-Key-
|
||||||
|
Dedup). Verlustfrei – kein bestehender Empfänger fällt beim
|
||||||
|
Umschalten auf Forwarding raus. Import-Fehler werden geloggt,
|
||||||
|
aber der eigentliche Sync läuft trotzdem.
|
||||||
|
|
||||||
- [x] **🔒 Pentest 81.1 (MEDIUM): Self-Forward erzeugte Mail-Loop am Provider**
|
- [x] **🔒 Pentest 81.1 (MEDIUM): Self-Forward erzeugte Mail-Loop am Provider**
|
||||||
- Bug: User konnte die Stressfrei-Adresse selbst (z.B.
|
- Bug: User konnte die Stressfrei-Adresse selbst (z.B.
|
||||||
`max.mustermann@stressfrei-wechseln.net`) als zusätzliches
|
`max.mustermann@stressfrei-wechseln.net`) als zusätzliches
|
||||||
|
|||||||
Reference in New Issue
Block a user