Zum Inhalt

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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
}

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