mail — Mail-Versand¶
Skripte versenden E-Mails über das Objekt mail: als kurze Textmail, mit
HTML, mit Anhängen (etwa dem Formular als PDF) und mit
Ad-hoc-Links, über die der Empfänger direkt zum Datensatz
kommt.
Die Verbindung zum Mailserver richtest du unter System-Administration → Schnittstellen & Verteilung → E-Mail-Konfiguration ein; Skripte haben damit nichts zu tun. Versendet wird immer über die Warteschlange.
Die einfachste Form¶
mail.send({
to: "team@example.de",
subject: "Neue Bestellung #" + ctx.instanceId,
body: "Bitte bearbeiten."
});
Die Kurzform kennt to, subject, body (oder gleichbedeutend text)
und from. Mehrere Empfänger trennst du in to mit Komma oder Semikolon.
Ohne from gilt der Standard-Absender. Für HTML, Kopie-
Empfänger oder Anhänge nimmst du mail.Message.
mail.Message¶
var msg = new mail.Message();
msg.from = "robot@example.de";
msg.to = ["a@example.de", "b@example.de"];
msg.cc = "chefin@example.de";
msg.subject = "Bericht " + new Date().format("yyyy-MM-dd");
msg.text = "Text-Variante.";
msg.html = "<p>HTML-Variante mit <b>Hervorhebung</b>.</p>";
msg.setHeader("X-KC-Source", "Mahnwesen");
mail.send(msg);
mail.newMessage() liefert dasselbe wie new mail.Message().
| Eigenschaft | Typ | Bedeutung |
|---|---|---|
from |
String | Absender |
sender |
String | abweichende Sender-Identität |
to |
String oder Array | Empfänger |
cc |
String oder Array | Kopie |
bcc |
String oder Array | Blindkopie |
replyTo |
String oder Array | Antwortadresse |
subject |
String | Betreff |
text |
String | Text-Inhalt |
html |
String | HTML-Inhalt |
content |
MessageMultipart |
Inhalt mit Anhängen (siehe unten) |
| Methode | Wirkung |
|---|---|
msg.setHeader(name, wert) |
Kopfzeile setzen (überschreibt) |
msg.addHeader(name, wert) |
Kopfzeile zusätzlich anhängen |
msg.getHeader(name) |
Kopfzeile lesen |
msg.removeHeader(name) |
Kopfzeile entfernen |
Setzt das Skript text und html, verschickt KCForms beide als
Alternativen (multipart/alternative); das Mailprogramm zeigt, was es
kann. Nur text oder nur html ergibt eine reine Text- bzw. HTML-Mail.
Text, HTML und beides¶
Reine Textmail:
var msg = new mail.Message();
msg.to = "kunde@example.de";
msg.subject = "Terminbestätigung";
msg.text = "Guten Tag,\n\nIhr Termin ist bestätigt.\n\nViele Grüße";
mail.send(msg);
Reine HTML-Mail:
var msg = new mail.Message();
msg.to = "kunde@example.de";
msg.subject = "Terminbestätigung";
msg.html = "<h2>Terminbestätigung</h2>"
+ "<p>Ihr Termin ist <b>bestätigt</b>.</p>";
mail.send(msg);
Text und HTML mit Anhang — dafür steckt eine Alternative (Text + HTML) in einem Multipart mit Anhängen:
var alt = new mail.MessageMultipart("alternative");
alt.addText("Ihr Termin ist bestätigt.");
alt.addHTML("<p>Ihr Termin ist <b>bestätigt</b>.</p>");
var mp = new mail.MessageMultipart(); // mixed
mp.addMultipart(alt, null); // Inhalt: Text/HTML
mp.addOutput("termin.pdf"); // Anhang: Formular als PDF
var msg = new mail.Message();
msg.to = "kunde@example.de";
msg.subject = "Terminbestätigung";
msg.content = mp;
mail.send(msg);
Eingebettete Bilder im HTML verweisen über eine Content-ID (cid:):
var mp = new mail.MessageMultipart("related");
mp.addHTML("<p>Logo:<br><img src='cid:logo0'></p>");
mp.addBytes("logo.png", fs["/vorlagen/uni-logo.png"].readBytes(), "image/png", "logo0");
// msg.content = mp; mail.send(msg);
Absender¶
Setzt das Skript kein from, bestimmt KCForms den Absender so:
mail.defaultFrom = "x@example.de"im Skript — gilt für diesen Skript-Lauf.- die E-Mail-Adresse des angemeldeten Benutzers (
ctx.user.email). - die Default-Absenderadresse für Mails aus System-Administration → Betrieb & Überwachung → System-Einstellungen (derselbe Wert wie der Standard-Absender in der E-Mail-Konfiguration).
Die Kurzform mail.send({ … }) nimmt ohne from direkt die
Default-Absenderadresse (Punkt 3).
Immer einen Standard-Absender eintragen
Viele Mailserver lehnen Nachrichten ohne gültigen, zum Konto passenden
Absender ab. Mit einer eingetragenen Default-Absenderadresse ist jede
Skript-Mail auf der sicheren Seite. Soll eine Mail ausdrücklich „aus
dem System-Postfach" kommen, auch wenn der Benutzer eine eigene Adresse
hat, setze msg.from bzw. mail.defaultFrom selbst.
Anhänge — MessageMultipart¶
Anhänge laufen immer über ein MessageMultipart. Der Text kommt als
erster Teil hinein, die Anhänge danach:
var mp = new mail.MessageMultipart(); // multipart/mixed
mp.addText("Im Anhang: PDF und XML.");
mp.addOutput("Beleg.pdf"); // Formular als PDF
mp.addData("Beleg.xml"); // Formulardaten als XML
var msg = new mail.Message();
msg.to = ctx.user.email;
msg.subject = "Beleg zur Bestellung";
msg.content = mp;
mail.send(msg);
| Methode | Was sie tut |
|---|---|
addText(text [, cid]) / addHTML(html [, cid]) |
Text- bzw. HTML-Teil |
add(part) |
fertigen Teil anhängen (new mail.MessagePart(text)) |
addMultipart(multipart, cid) |
verschachteltes Multipart (z. B. Text/HTML-Alternative) |
addBytes(name, bytes, typ, cid) |
beliebige Bytes als Datei |
addAttachment(anlage [, name, typ, cid]) |
eine Dateianlage aus ctx.attachments |
addAttachments(ctx.attachments [, cidMuster]) |
alle Dateianlagen auf einmal |
addOutput(name [, format, typ, cid, sprache]) |
das aktuelle Formular als PDF |
addData(name [, encoding, cid]) |
Formulardaten als XML |
addJson(name [, cid]) |
Formulardaten als JSON |
addResource(fsDatei [, name, typ, cid]) |
Datei aus der fs-Sandbox |
formatbeiaddOutputist"pdf"(andere Werte werden abgelehnt).encodingbeiaddDataistUTF-8(Standard) oderISO-8859-1.cidist die Content-ID, über die HTML den Teil einbettet (<img src="cid:…">); meist bleibt sie leer.- Das
cidMusterbeiaddAttachmentsdarf${index}und${name}enthalten, z. B."anl-${index}".
PDF in einer bestimmten Sprache¶
Der fünfte Parameter von addOutput legt die Ausdrucks-Sprache fest
("de", "sv", "en" oder jede im Formular gepflegte Sprache).
Beschriftungen, Seitentitel und Makros im PDF folgen dann dieser Sprache —
praktisch, um den Anhang in der Sprache des Empfängers zu verschicken:
var lang = ctx.form.sprache || "de"; // z. B. aus einem Auswahlfeld
var mp = new mail.MessageMultipart();
mp.addText("…");
mp.addOutput("Ausdruck_" + lang + ".pdf", "pdf", null, null, lang);
Vorrang: sprache-Parameter → ctx.docLang → ctx.lang (siehe
ctx). Dasselbe Argument kennt pdf.render(lang).
Formulardaten als JSON¶
addJson hängt die Formulardaten als JSON-Datei an — ein Format, das die
meisten Umsysteme direkt verarbeiten. Interne Schlüssel wie
_changedField fehlen darin:
{
"form": "vorgang",
"title": "Neuer Vorgang",
"instanceId": 42,
"data": { "betreff": "…", "menge": 3, "positionen": [ … ] }
}
addOutput, addData, addJson brauchen ein Formular
Diese drei arbeiten mit dem Formular des Skripts (ctx.formId) und
dem aktuellen Stand von ctx.form. In der Skript-Konsole, in Jobs und
in REST-Services gibt es kein Formular — dort addBytes oder
addResource verwenden.
Beispiel: alle Dateianlagen weiterleiten¶
var mp = new mail.MessageMultipart();
mp.addText("Datensatz #" + ctx.instanceId + " mit allen Anlagen.");
mp.addOutput("Datensatz.pdf");
mp.addAttachments(ctx.attachments);
var msg = new mail.Message();
msg.to = "archiv@example.de";
msg.subject = "Datensatz #" + ctx.instanceId;
msg.content = mp;
mail.send(msg);
Ad-hoc-Links¶
mail.newAdhocInvocation() erzeugt einen Link, der den aktuellen
Datensatz direkt öffnet — typisch für „Hier geht's zu Ihrem Antrag" oder
eine Freigabe per Mail. Der Aufruf liefert { id, url }:
// onSubmit
var inv = mail.newAdhocInvocation();
var msg = new mail.Message();
msg.to = ctx.form.kontaktEmail;
msg.subject = "Ihre Bestellung";
msg.text = "Status und Details:\n${url}";
mail.send(msg, inv); // ${url} wird durch inv.url ersetzt
${url} wird nur ersetzt, wenn du inv (oder ein anderes Objekt mit
dem Schlüssel url) als zweites Argument an mail.send übergibst. Die
Ersetzung gilt für Betreff, Text, HTML und die Textteile eines
Multiparts. Das ist kein
Makro, sondern nur diese einfache
Ersetzung.
Der Link beginnt mit der Öffentlichen Basis-URL aus den
System-Einstellungen. Ist sie leer, entsteht nur ein relativer Pfad
(/adhoc/…), der im Mailprogramm nicht anklickbar ist.
Wer den Link öffnen darf¶
var ablauf = new Date();
ablauf.setDate(ablauf.getDate() + 7); // 7 Tage gültig
var inv = mail.newAdhocInvocation("anonymous", ablauf);
| Erster Parameter | Wer darf öffnen |
|---|---|
"any" (Standard) |
jeder angemeldete Benutzer; wer nicht angemeldet ist, sieht zuerst die Anmeldung |
"anonymous" |
jeder, auch ohne Anmeldung — außer die System-Einstellung verlangt für Ad-hoc-Links eine Anmeldung |
"public" |
immer ohne Anmeldung, unabhängig von der System-Einstellung; für öffentlich verlinkte Formulare |
"user:anna,ben" |
nur die genannten Benutzer (Loginnamen) |
"group:personal" |
nur Mitglieder der genannten Gruppen |
Der zweite Parameter setzt ein Ablaufdatum; ohne ihn bleibt der Link gültig. Wie sich Ad-hoc-Links global verhalten (Anmeldung erzwingen, Sprache für anonyme Besucher …), steht unter System-Administration → Betrieb & Überwachung → System-Einstellungen, Abschnitt Ad-hoc-Links — Anmeldung. Links für Webseiten ohne Mail beschreibt Web-Links.
„anonymous" und „public" bewusst einsetzen
Wer einen solchen Link kennt, öffnet den Datensatz ohne Anmeldung —
auch wenn die Mail weitergeleitet wurde. Für Daten, die nicht jeder
sehen soll, "any" oder user:/group: verwenden und ein
Ablaufdatum setzen.
E-Mail-Ausgang (Warteschlange)¶
mail.send(...) verschickt nicht sofort, sondern legt die fertige
Nachricht samt Anhängen in eine Warteschlange. Ein Hintergrunddienst
stellt sie zu (alle 15 Sekunden). Für Skripte heißt das:
mail.sendkehrt sofort zurück — auch wenn der Mailserver langsam oder nicht erreichbar ist. Speichern und Absenden werden nicht gebremst.- Keine Mail geht verloren: Scheitert die Zustellung, versucht KCForms
es mit wachsenden Abständen erneut (bis zu 8 Versuche). Eine endgültige
Ablehnung durch den Mailserver (z. B.
550) wird nicht wiederholt. - Den Stand jeder Mail (wartend, in Zustellung, gesendet, gescheitert) zeigt System-Administration → Schnittstellen & Verteilung → E-Mail-Ausgang; dort lassen sich gescheiterte Mails erneut anstoßen.
Welche Fehler das Skript sieht¶
Sofort — also beim mail.send — prüft KCForms nur, was sich ohne
Mailserver entscheiden lässt: fehlende oder ungültige Adressen und die
Empfänger-Whitelist. Solche Fehler wirft mail.send; aus
einem Hook erscheinen sie als Fehlermeldung im Formular. Wer sie selbst
behandeln will:
try {
mail.send({ to: ctx.form.empfEmail, subject: 'Zustellung', body: '…' });
} catch (e) {
ctx.addError('empfEmail', 'Versand nicht möglich: ' + e.message);
}
Ob der Mailserver die Nachricht annimmt, erfährt das Skript nicht — das zeigt der E-Mail-Ausgang.
Ohne Warteschlange
Mit kcforms.mail.spool.enabled=false sendet KCForms direkt. Dann
wirft mail.send auch Ablehnungen des Mailservers (SMTP 5xx,
Anmeldefehler) sofort; ist der Mailserver gar nicht erreichbar, landet
die Mail nur im Protokoll. Für den Betrieb ist die Warteschlange die
bessere Wahl. Den Verbindungstest in der E-Mail-Konfiguration sendet
KCForms immer direkt, damit Konfigurationsfehler sofort auffallen.
Stolperfallen¶
- Mehrere Empfänger als Array angeben:
msg.to = ["a@example.de", "b@example.de"]. Ein String"a@example.de, b@example.de"gilt beimail.Messageals eine Adresse (nur die Kurzformmail.send({ to: … })trennt an Komma und Semikolon). - Kein Absender ermittelbar — die meisten Mailserver lehnen die Mail dann ab. Abhilfe: Default-Absenderadresse eintragen (siehe Absender).
- In der Entwicklungsumgebung gehen Mails an Mailpit
(
http://localhost:8025) — nichts verlässt den Rechner. Ist ein echter Mailserver eingetragen, gehen die Mails wirklich hinaus. - Empfänger-Domain-Whitelist (in der E-Mail-Konfiguration): Ist sie
gefüllt, lehnt
mail.sendjeden Empfänger (to/cc/bcc) außerhalb der erlaubten Domains ab. Leer = keine Beschränkung. Nützlich in Testsystemen gegen versehentliche Mails an echte Kunden.
Vollständiges Beispiel: Bestätigung mit Link und PDF¶
// onSubmit
var inv = mail.newAdhocInvocation("any");
var mp = new mail.MessageMultipart();
mp.addText("Hallo " + ctx.form.kontaktName + ",\n\n"
+ "vielen Dank für Ihre Bestellung. Den Stand sehen Sie jederzeit hier:\n\n"
+ "${url}\n\nDer Beleg hängt an.\n");
mp.addOutput("Beleg.pdf");
var msg = new mail.Message();
msg.to = ctx.form.kontaktEmail;
msg.subject = "Ihre Bestellung Nr. " + ctx.instanceId;
msg.content = mp;
mail.send(msg, inv);
view.add(new view.Message("Bestätigung an " + ctx.form.kontaktEmail + " gesendet."));