E-Mail¶
Mit mail verschickt ein Skript E-Mails: eine kurze Benachrichtigung, eine
Bestätigung an den Antragsteller, einen Bericht mit Anhang. Den Mailserver
richtet der Admin einmal unter E-Mail-Konfiguration ein — im Skript
musst du dich darum nicht kümmern.
Ausführliches dazu: mail — Mail-Versand.
Gefahrlos testen
mail.send legt die Mail in eine Warteschlange; zugestellt wird sie
wenige Sekunden später. Auf einem Testsystem sollte der Admin eine
Empfänger-Whitelist setzen (nur die eigene Domain) — dann kann keine
Übungsmail versehentlich bei Kunden landen. Die Adressen in den
Beispielen enden auf beispiel.example; diese Domain gibt es nicht.
Einsteiger¶
1. Eine kurze Mail senden¶
Die Kurzform braucht nur Empfänger, Betreff und Text.
mail.send({
to: "team@beispiel.example",
subject: "Neuer Antrag eingegangen",
body: "Bitte im Formularsystem nachsehen."
});
2. An mehrere Empfänger¶
In der Kurzform trennst du mehrere Adressen mit Komma.
mail.send({
to: "a@beispiel.example, b@beispiel.example",
subject: "Info an alle",
body: "Kurze Info an das ganze Team."
});
3. Die ausführliche Form mit mail.Message¶
Für alles, was über die Kurzform hinausgeht, baust du eine Nachricht Schritt für Schritt.
var msg = new mail.Message();
msg.to = "kunde@beispiel.example";
msg.subject = "Ihre Anfrage";
msg.text = "Guten Tag,\n\nvielen Dank für Ihre Anfrage.\n\nFreundliche Grüße";
mail.send(msg);
\n ist ein Zeilenumbruch.
4. Formularwerte in Betreff und Text¶
var msg = new mail.Message();
msg.to = "buchhaltung@beispiel.example";
msg.subject = "Antrag von " + ctx.form.vorname + " " + ctx.form.name;
msg.text = "Betrag: " + $betrag.numFormat(null, "€", 0, 2, ",", ".", 3) + "\n"
+ "Eingegangen am " + new Date().format("dd.MM.yyyy 'um' HH:mm");
mail.send(msg);
numFormat macht aus dem rohen Feldwert einen Betrag, wie ihn der Empfänger
erwartet: "249,9" oder "249.90" werden beide zu 249,90 €. Ohne das
steht in der Mail, was gerade im Feld stand — alle
Angaben.
5. An den angemeldeten Benutzer¶
ctx.user.email ist die Adresse der Person, die gerade am Formular sitzt.
mail.send({
to: ctx.user.email,
subject: "Kopie Ihrer Eingabe",
body: "Hallo " + ctx.user.firstName + ", Ihre Daten sind eingegangen."
});
6. Einen Absender festlegen¶
Ohne Angabe verschickt KCForms im Namen des Benutzers bzw. mit der
Standard-Absenderadresse. Mit from bestimmst du selbst.
var msg = new mail.Message();
msg.from = "noreply@beispiel.example";
msg.to = "kunde@beispiel.example";
msg.subject = "Automatische Nachricht";
msg.text = "Bitte nicht auf diese Mail antworten.";
mail.send(msg);
7. Kopie und Blindkopie¶
cc sehen alle Empfänger, bcc sieht niemand.
var msg = new mail.Message();
msg.to = "antragsteller@beispiel.example";
msg.cc = "vorgesetzte@beispiel.example";
msg.bcc = "archiv@beispiel.example";
msg.subject = "Ihr Antrag wurde genehmigt";
msg.text = "Ihr Antrag ist genehmigt.";
mail.send(msg);
8. Eine HTML-Mail¶
Mit html statt text kannst du fett schreiben, Überschriften und Listen
verwenden.
var msg = new mail.Message();
msg.to = "kunde@beispiel.example";
msg.subject = "Terminbestätigung";
msg.html = "<h2>Terminbestätigung</h2>"
+ "<p>Ihr Termin am <b>20.10.2026 um 10 Uhr</b> ist bestätigt.</p>";
mail.send(msg);
Fortgeschritten¶
9. Text und HTML zusammen¶
Setzt du beides, zeigt jedes Mailprogramm die Variante, die es kann.
var msg = new mail.Message();
msg.to = "kunde@beispiel.example";
msg.subject = "Rechnung";
msg.text = "Ihre Rechnung über 99,00 € liegt bereit.";
msg.html = "<p>Ihre Rechnung über <b>99,00 €</b> liegt bereit.</p>";
mail.send(msg);
10. Nur senden, wenn eine gültige Adresse da ist¶
var adresse = String(ctx.form.email || "").trim();
if (/^[^@\s]+@[^@\s]+\.[a-z]{2,}$/i.test(adresse)) {
mail.send({ to: adresse, subject: "Bestätigung", body: "Danke!" });
log.info("Bestätigung gesendet");
} else {
log.info("Keine gültige E-Mail-Adresse – nicht gesendet");
}
11. Eine Textdatei anhängen¶
Anhänge laufen über ein MessageMultipart: erst der Text, dann die Anhänge.
Ein Anhang braucht Bytes — hier aus einer Datei der Sandbox.
fs["/beispiele/mail/hinweis.txt"].writeText("Bitte bis Freitag zurückschicken.");
var mp = new mail.MessageMultipart();
mp.addText("Im Anhang ein Hinweis.");
mp.addBytes("hinweis.txt", fs["/beispiele/mail/hinweis.txt"].readBytes(), "text/plain", null);
var msg = new mail.Message();
msg.to = "kunde@beispiel.example";
msg.subject = "Hinweis";
msg.content = mp;
mail.send(msg);
12. Eine CSV-Tabelle anhängen¶
Ein CSV-Printer liefert seine Bytes mit toByteArray().
var p = new csv.StandardPrinter({ separator: ";", bom: true });
p.println(["Artikel", "Menge"]);
p.println(["Stift", 10]);
p.println(["Block", 5]);
var mp = new mail.MessageMultipart();
mp.addText("Die Bestellliste als CSV-Datei.");
mp.addBytes("bestellung.csv", p.toByteArray(), "text/csv", null);
var msg = new mail.Message();
msg.to = "einkauf@beispiel.example";
msg.subject = "Bestellliste";
msg.content = mp;
mail.send(msg);
13. Das Formular als PDF anhängen¶
addOutput hängt den Ausdruck des aktuellen Formulars an — so, wie er
auch beim Drucken aussieht. Das funktioniert in Formular-Hooks, nicht in der
Skript-Konsole.
var mp = new mail.MessageMultipart();
mp.addText("Anbei der Antrag als PDF.");
mp.addOutput("Antrag.pdf");
var msg = new mail.Message();
msg.to = "sachbearbeitung@beispiel.example";
msg.subject = "Antrag " + ctx.form.name;
msg.content = mp;
mail.send(msg);
14. Die Formulardaten als JSON mitschicken¶
Für ein anderes Programm, das die Daten maschinell weiterverarbeitet.
var mp = new mail.MessageMultipart();
mp.addText("Datensatz im Anhang.");
mp.addJson("daten.json");
var msg = new mail.Message();
msg.to = "schnittstelle@beispiel.example";
msg.subject = "Datenübergabe";
msg.content = mp;
mail.send(msg);
15. Eine Datei aus der Sandbox anhängen¶
addResource nimmt direkt ein Datei-Objekt.
var agb = fs["/beispiele/mail/agb.txt"];
agb.writeText("Allgemeine Geschäftsbedingungen (Beispiel)");
var mp = new mail.MessageMultipart();
mp.addText("Unsere AGB im Anhang.");
mp.addResource(agb, "AGB.txt", "text/plain", null);
var msg = new mail.Message();
msg.to = "kunde@beispiel.example";
msg.subject = "Unsere AGB";
msg.content = mp;
mail.send(msg);
16. Antworten an eine andere Adresse leiten¶
Die Mail kommt vom System, Antworten sollen aber beim Team landen.
var msg = new mail.Message();
msg.from = "noreply@beispiel.example";
msg.replyTo = "service@beispiel.example";
msg.to = "kunde@beispiel.example";
msg.subject = "Ihre Serviceanfrage";
msg.text = "Antworten Sie einfach auf diese Mail.";
mail.send(msg);
17. Eine Mail als wichtig markieren¶
Zusatzangaben stehen im Header der Mail.
var msg = new mail.Message();
msg.to = "leitung@beispiel.example";
msg.subject = "Dringend: Freigabe benötigt";
msg.text = "Bitte heute noch freigeben.";
msg.setHeader("X-Priority", "1");
msg.setHeader("Importance", "high");
log.info("Priorität: " + msg.getHeader("X-Priority"));
mail.send(msg);
18. Fehler beim Senden abfangen¶
Fehlt der Empfänger oder ist die Adresse ungültig, meldet mail.send sofort
einen Fehler. Mit try … catch bleibt das Formular bedienbar.
try {
mail.send({ to: ctx.form.email, subject: "Test", body: "…" });
} catch (e) {
ctx.addError("email", "Die Mail konnte nicht verschickt werden: " + e.message);
}
Ob der Mailserver die Mail später wirklich zustellt, zeigt System-Administration → E-Mail-Ausgang.
Profi¶
19. Persönliche Mails an eine Liste¶
Jeder Empfänger bekommt eine eigene Mail mit seinem Namen. Die Liste kommt hier aus der Datenbank.
var empfaenger = db.query(
"SELECT FIRST_NAME, EMAIL FROM USERS WHERE EMAIL IS NOT NULL ORDER BY LOGIN_NAME");
var n = 0;
empfaenger.slice(0, 3).forEach(function (u) { // für die Übung nur drei
mail.send({
to: u.email,
subject: "Einladung zur Schulung",
body: "Hallo " + u.first_name + ",\n\nwir laden dich herzlich ein."
});
n++;
});
log.info(n + " Mails vorbereitet");
20. Eine Tabelle als HTML¶
Positionen einer Detail-Tabelle als HTML-Tabelle. Werte aus Eingaben werden maskiert, damit niemand eigenes HTML einschleusen kann.
function html(text) {
return String(text == null ? "" : text)
.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
}
var zeilen = (ctx.form.positionen || []).map(function (p) {
return "<tr><td>" + html(p.artikel) + "</td><td style='text-align:right'>" + html(p.menge) + "</td></tr>";
}).join("");
var msg = new mail.Message();
msg.to = "einkauf@beispiel.example";
msg.subject = "Bestellung";
msg.html = "<table border='1' cellpadding='4'><tr><th>Artikel</th><th>Menge</th></tr>" + zeilen + "</table>";
log.info(msg.html);
mail.send(msg);
21. Nur auf dem Produktivsystem wirklich senden¶
Auf Test- und Entwicklungssystemen soll nichts hinausgehen. Die Kennung des
Systems steht in ctx.system.id (gepflegt in den System-Einstellungen).
var msg = { to: "kunde@beispiel.example", subject: "Rechnung", body: "…" };
if (ctx.system.id === "PROD") {
mail.send(msg);
} else {
log.info("System " + ctx.system.id + ": Mail an " + msg.to + " nicht gesendet");
}
22. Die Mail in der Sprache des Empfängers¶
var texte = {
de: { betreff: "Ihre Bestellung", text: "Vielen Dank für Ihre Bestellung." },
en: { betreff: "Your order", text: "Thank you for your order." },
sv: { betreff: "Din beställning", text: "Tack för din beställning." }
};
var sprache = { DE: "de", AT: "de", CH: "de", SE: "sv" }[ctx.form.land] || "en";
var t = texte[sprache];
mail.send({ to: "kunde@beispiel.example", subject: t.betreff, body: t.text });
23. Eine Textvorlage mit Platzhaltern¶
Der Text liegt als Vorlage vor; {name} & Co. werden durch Werte ersetzt.
So kann die Fachabteilung den Text pflegen, ohne das Skript zu ändern — etwa
in einer Datei oder den Properties.
var vorlage = "Hallo {vorname} {name},\n\nwir haben {betrag} € erhalten.\n\nIhr Team";
function fuelle(text, werte) {
return text.replace(/\{(\w+)\}/g, function (ganz, name) {
return werte[name] != null ? werte[name] : ganz;
});
}
var text = fuelle(vorlage, { vorname: ctx.form.vorname, name: ctx.form.name, betrag: ctx.form.betrag });
log.info(text);
mail.send({ to: "kunde@beispiel.example", subject: "Zahlungseingang", body: text });
24. Ein eingebettetes Bild¶
Das Bild wird über eine Content-ID (cid:) im HTML angezeigt, statt
als Anhang zu erscheinen.
fs["/beispiele/mail/logo.svg"].writeText(
"<svg xmlns='http://www.w3.org/2000/svg' width='120' height='30'><text x='0' y='20'>KCForms</text></svg>");
var mp = new mail.MessageMultipart("related");
mp.addHTML("<p>Viele Grüße<br><img src='cid:logo1' alt='Logo'></p>");
mp.addBytes("logo.svg", fs["/beispiele/mail/logo.svg"].readBytes(), "image/svg+xml", "logo1");
var msg = new mail.Message();
msg.to = "kunde@beispiel.example";
msg.subject = "Mit Logo";
msg.content = mp;
mail.send(msg);
25. Vertrauliches als verschlüsseltes ZIP¶
Ein passwortgeschütztes ZIP als Anhang. Das Passwort teilst du auf einem anderen Weg mit — nie in derselben Mail.
var inhalt = zip.create([
{ name: "gehalt.txt", data: "Vertrauliche Daten" }
], { password: "Sommer2026!", encryption: "aes" });
var mp = new mail.MessageMultipart();
mp.addText("Die Unterlagen im Anhang. Das Passwort erhalten Sie telefonisch.");
mp.addBytes("unterlagen.zip", inhalt, "application/zip", null);
var msg = new mail.Message();
msg.to = "personal@beispiel.example";
msg.subject = "Vertrauliche Unterlagen";
msg.content = mp;
mail.send(msg);
fs["/beispiele/mail"].remove(true); // Übungsordner aufräumen