Sending Alarm Emails in WinCC Professional via VBS Scripts
Email notification on alarm events remains a frequent requirement in WinCC Runtime Professional (TIA Portal) projects. Unlike WinCC Comfort/Advanced, where System Functions such as SendEmail exist on the HMI panel, the WinCC Professional (SCADA) runtime does not provide a built-in SMTP client in the same way. The robust, field-proven approach is to bind a VBScript to the alarm event, format the alarm payload from MSG_RTDATA_STRUCT, and dispatch the message through an external command-line SMTP client. The reference solution described here uses Blat, but the same template can be swapped for PowerShell, CDO, or a vendor mailer.
1. WinCC Professional vs WinCC Advanced/Comfort
Engineers frequently migrate HMI projects from Comfort panels to SCADA systems and assume the same function set is available. The email story is one of the first places this assumption breaks.
| Runtime | Target | Email Method | Limitation |
|---|---|---|---|
| WinCC RT Advanced | Comfort / Mobile Panels |
SendEmail System Function |
Single function call; limited SSL/TLS control |
| WinCC RT Professional | PC-based SCADA | VBScript + external SMTP tool (Blat, PowerShell, CDO.Message) | No native function; you must orchestrate it |
| WinCC V7 (Classic) | PC-based SCADA | C / VBS with gsmgfunc (legacy) |
Documented in Siemens FAQ 53385716 |
The distinction matters: a script that calls the wrong runtime's function set will compile but silently no-op. Always verify the runtime target in the project's device configuration before deciding on the email path.
2. Prerequisites
- WinCC Professional V13 or later (V15, V16, V17, V18, V19, V20 are confirmed compatible).
- WinCC Runtime Professional installed on the target PC, licensed with at least RC 1024 tags or RC 8192 tags depending on scope.
-
Blat command-line mailer (Windows 32/64-bit) copied to a fixed path such as
D:\larmer\blat.exe. Download from the official site blat.net. - SMTP relay reachable from the SCADA PC (mail server, Office 365 relay, internal Exchange relay, or mail.ru / gmail / smtp.mail.ru depending on operator policy). Port 25 for plain SMTP, 465/587 for SSL/TLS.
- VBScript execution enabled in the runtime project (default in RT Professional).
-
User rights on the RT PC: the runtime service account must have write access to the log directory and execute rights for
blat.exe.
3. Alarm Logging Basics in RT Professional
Alarms in WinCC Professional fall into two families: discrete (bit-triggered) and analog (limit-value based on a process tag). For analog alarms, a limit violation raises an alarm with a message number, the associated tag value, and the configured text. The alarm is recorded in the alarm log, which is documented in the official TIA Portal V20 alarm logging reference.
Alarm logging is a system-created mechanism. You do not need to author the log structure manually, but you must define:
- The alarm classes (Errors, Warnings, System, etc.) and their acknowledgement behavior.
- The message configuration: message number, message text (with text list fields for tag values), trigger tag or condition.
- The logging destination: Alarm log on a circular log path, default
<Project path>\Logging.
4. Installing and Configuring Blat
Blat is a free, lightweight SMTP client. On the SCADA PC, perform the following:
- Copy
blat.exe,blat.dll, andblat.libto a stable directory, for exampleD:\larmer\. - Open a command prompt and install the default profile:
This stores profile data in the registry underblat -install smtp.yourdomain.com [email protected] -port 587 -u "smtpuser" -pw "smtppass"HKLM\Software\Public Domain\Blat. - Send a test message:
blat -body "WinCC test" -subject "Alarm channel test" -to [email protected] - If the test mail arrives, Blat is operational. If it does not, check
blat -debug -log D:\larmer\blat.logoutput.
blat.exe as a mailer with suspicious behaviour. Add an explicit allow-list entry for the binary on the SCADA host.5. Reading Alarm Data with MSG_RTDATA_STRUCT
When a VBScript is bound to an alarm event (OnCome, OnGo, OnAcknowledge), the runtime injects a parameter object describing the alarm. The structure is MSG_RTDATA_STRUCT, and the canonical field list is:
| Field | Type | Meaning |
|---|---|---|
MSG_NR |
Long | Configured alarm number |
MSG_STATE |
Byte | Alarm state: 1=Came In, 2=Went Out, 3=Acknowledge |
MSG_TEXT |
String | Resolved alarm text (with substituted tag values) |
MSG_TIME |
Date | Time the alarm was raised |
MSG_MS |
Long | Milliseconds component of the timestamp |
MSG_PRTY |
Byte | Priority (0 = lowest) |
MSG_CLASS |
String | Alarm class name (e.g. "Error", "Warning") |
MSG_VAR1..8 |
String | Substituted process values from the configured text list |
You can pull these into VBScript variables inside the alarm event handler. The pattern is:
Sub OnAlarm_Came(alarm)
Dim sText, sTime, sClass
sText = alarm.MSG_TEXT
sTime = alarm.MSG_TIME
sClass = alarm.MSG_CLASS
' build email body here
End Sub
MSG_RTDATA_STRUCT is documented in the WinCC Professional help under "Void state (MSG_RTDATA_STRUCT Parameter)". The parameter object is only present when the script is bound directly to an alarm event. If you trigger a tag and let a separate scheduled task react to that tag, the alarm structure is not available; you must persist the data via an internal tag and read it in the second script.6. Building the Email-Send Script
Create a project-wide VBScript function that accepts the alarm text and a target recipient list, then shells out to Blat. The recommended approach uses WScript.Shell.Run with bWaitOnReturn = False so the alarm event is not blocked while SMTP negotiates.
' SendMail.vbs - project-wide function
Sub SendMail(sSubject, sBody, sTo)
Dim WshShell, my_MailCmd, sProfile
Set WshShell = CreateObject("WScript.Shell")
sProfile = "-profile" ' use stored Blat profile
my_MailCmd = "D:\larmer\blat.exe " & sProfile & _
" -to " & Chr(34) & sTo & Chr(34) & _
" -subject " & Chr(34) & sSubject & Chr(34) & _
" -body " & Chr(34) & sBody & Chr(34) & _
" -debug -log " & Chr(34) & "D:\larmer\TEST-blat.log" & Chr(34)
WshShell.Run my_MailCmd, 0, False
End Sub
Alternative construction with explicit server parameters (no profile):
my_MailCmd = "D:\larmer\blat.exe" & _
" -server smtp.yourdomain.com:587" & _
" -u smtpuser -pw SmtpP@ss" & _
" -f [email protected]" & _
" -to " & Chr(34) & sTo & Chr(34) & _
" -subject " & Chr(34) & sSubject & Chr(34) & _
" -body " & Chr(34) & sBody & Chr(34) & _
" -debug -log " & Chr(34) & "D:\larmer\TEST-blat.log" & Chr(34)
Chr(34) (literal double-quote). Subject and body in alarm messages frequently contain commas, semicolons, and Unicode characters that break an unquoted command line.7. Binding the Script to an Analog Alarm
- In the TIA project tree, open "HMI alarms" → "Analog alarms".
- Add an alarm with a message number (e.g.
1001), a message text such as"Tank level high: %s", and a trigger tag (e.g.TankLevel) with a limit value (e.g.90.0) and trigger mode "On rising limit violation". - In the alarm's "Events" tab, expand "OnCome" (raised).
- Click the right-hand function selector and choose "VBScript function", then write a small handler:
Sub OnAnalogAlarm_Came(alarm) Dim sSubj, sBody, sTo sTo = "[email protected]" sSubj = "[WinCC] " & alarm.MSG_CLASS & " #" & alarm.MSG_NR & " - " & alarm.MSG_TIME sBody = alarm.MSG_TEXT & vbCrLf & _ "State: " & alarm.MSG_STATE & vbCrLf & _ "Tag value: " & alarm.MSG_VAR1 Call SendMail(sSubj, sBody, sTo) End Sub - Compile, download to the RT PC, and start runtime.
8. Triggering Multiple Scripts from a Single Alarm
WinCC Professional only allows one event handler per alarm state. If you need to both send an email and write the alarm text to a file, you cannot bind two VBS actions to the same OnCome event directly. The documented workaround is a tag-based trigger:
- Define an internal HMI tag, e.g.
AlarmEmailTrigger(Boolean, internal). - On the alarm's OnCome event, configure a "Set tag" system function that sets
AlarmEmailTrigger = TRUE. - Bind the email script to a tag change on
AlarmEmailTriggerin the "Tag triggers" editor (with edge detection: 0 → 1). - From the same trigger, a second script (file writer) is also invoked by adding both to the trigger's event chain.
FALSE at the end of the script chain; otherwise the next alarm will not retrigger (edge detection). Add a SmartTags("AlarmEmailTrigger") = False at the end of the final script.9. Writing the Alarm Text to a File
A persistent log complements the email channel and supports audit requirements:
Sub WriteAlarmToFile(alarm)
Dim oFSO, oFile, sPath
sPath = "D:\larmer\alarms_" & Year(Now) & "_" & Right("0" & Month(Now),2) & ".log"
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oFile = oFSO.OpenTextFile(sPath, 8, True) ' 8 = ForAppending
oFile.WriteLine FormatDateTime(alarm.MSG_TIME, vbGeneralDate) & _
" [" & alarm.MSG_CLASS & "] #" & alarm.MSG_NR & _
" " & alarm.MSG_TEXT
oFile.Close
Set oFile = Nothing
Set oFSO = Nothing
End Sub
10. Reading Date and Time Outside the Alarm Context
When a script is bound to a scheduled task rather than an alarm event, the MSG_RTDATA_STRUCT parameter is unavailable. The native VBScript Now function returns the current date and time in the locale's format:
Dim sNow
sNow = FormatDateTime(Now, vbGeneralDate)
' Result: "01/15/2025 14:23:47" (en-US locale)
For deterministic formatting independent of locale, use Year(Now), Month(Now), Day(Now), Hour(Now), Minute(Now), Second(Now) and concatenate with leading zeros via Right("0" & n, 2).
11. Verifying the Channel
- Force the limit violation in the PLC (or use the simulator in TIA).
- Watch
D:\larmer\TEST-blat.login real time withGet-Content -Wait(PowerShell) or a tail utility. - Expected log entries:
Blat v3.2.20 (build : Mar 18 2017 12:17:32) Connecting to smtp.yourdomain.com on port 587 Connected, sending login Sending email to [email protected] Message sent successfully - Confirm delivery in the recipient mailbox.
- Inspect the alarm log on disk (default
<ProjectPath>\Logging\AlarmLog_*.csv) to confirm the alarm was raised and acknowledged.
12. Troubleshooting Matrix
| Symptom | Likely Root Cause | Action |
|---|---|---|
| No email, no log file | Script never fires; MSG_RTDATA_STRUCT not populated |
Verify event binding; use a temporary MsgBox to confirm execution |
| Log file present, "server not found" | DNS or firewall blocks SMTP | Test telnet smtp.yourdomain.com 25 from the SCADA host |
| Log file shows "auth failed" | Wrong credentials, app password missing, MFA enforced | Reconfigure with a service-account app password; check -u -pw in command line |
Email body shows %s literally |
Text list field not configured for the alarm | Open the alarm properties, link text list fields to the trigger tag in "Process values" |
| Subject truncated at first space | Missing Chr(34) quotes |
Re-wrap subject and body in literal double-quotes |
Script error 800A0401 on strcat
|
C-syntax helper used outside C editor | Use VBS & for concatenation; strcat is a WinCC V7 C function, not VBS |
| Email fires only on first alarm | Internal trigger tag not rearmed | Reset the trigger tag to FALSE at the end of the script |
| RT Advance project, no SMTP function | Wrong runtime target | Verify the device type; on Comfort panels use SendEmail system function instead |
| "blat.exe is not a valid Win32 application" | Wrong architecture Blat (32 vs 64-bit) on 64-bit OS | Use the matching build; place DLL in the same directory as EXE |
13. Hardening the Configuration
-
TLS / SSL: Blat supports STARTTLS via
-tlson the-installcommand. For pure TLS on port 465, wrap Blat instunnelor migrate toSend-MailMessagein PowerShell. - Credentials in script: Avoid hard-coding passwords in VBS. Use the Blat profile (registry) or a credential manager.
- Rate limiting: For flapping tags, debounce the alarm event in the PLC (hysteresis) or filter in VBS (only send if no email in the last N seconds).
- Heartbeat: Periodically send a "Runtime alive" mail from a scheduled task to confirm the channel is healthy.
-
Time synchronisation: Ensure the SCADA PC uses NTP; otherwise alarm timestamps in
MSG_TIMEwill drift.
Can WinCC Professional send emails without an external SMTP tool?
Yes. The same VBS pattern works with PowerShell's Send-MailMessage cmdlet or with the COM object CDO.Message. Replace the WshShell.Run line with the appropriate WScript.Shell.Exec or CreateObject("CDO.Message") call. The alarm event binding and MSG_RTDATA_STRUCT consumption remain identical.
Why does my VBScript fire but no log file appears in D:\larmer\?
The most common cause is the runtime user lacking write permission on D:\larmer\. WinCC Runtime Professional runs as a Windows service by default; the service account must have write access. Grant the account Modify rights on the directory, or use C:\Users\<RTServiceUser>\AppData\Local\WinCC\ instead.
How do I send to multiple recipients?
Pass a comma-separated list inside the quoted -to argument: -to "[email protected], [email protected]". Blat accepts a list with a delimiter. If your SMTP relay enforces a recipient cap, split the recipients across separate Blat invocations inside a For Each loop.
Can I read the current tag value into the email body?
Yes. If the alarm is configured with a text list (e.g. "Level reached %s %%" bound to TankLevel), the substituted value is in alarm.MSG_VAR1 through MSG_VAR8. Alternatively, read the live tag with SmartTags("TankLevel") at the moment the script executes.
Does this work in TIA Portal V20?
Yes. The alarm scripting API, MSG_RTDATA_STRUCT, and VBScript runtime are present in every TIA Portal release from V13 through V20. Always refer to the current TIA Portal V20 alarm documentation for the latest field set, as Microsoft has occasionally deprecated older VBS APIs.