Zum Inhalt

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:

  1. mail.defaultFrom = "x@example.de" im Skript — gilt für diesen Skript-Lauf.
  2. die E-Mail-Adresse des angemeldeten Benutzers (ctx.user.email).
  3. 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
  • format bei addOutput ist "pdf" (andere Werte werden abgelehnt).
  • encoding bei addData ist UTF-8 (Standard) oder ISO-8859-1.
  • cid ist die Content-ID, über die HTML den Teil einbettet (<img src="cid:…">); meist bleibt sie leer.
  • Das cidMuster bei addAttachments darf ${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);

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.

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.send kehrt 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 bei mail.Message als eine Adresse (nur die Kurzform mail.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.send jeden 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.
// 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."));