Sending Alarm Emails in WinCC Professional via VBS Scripts

David Krause11 min read
SiemensTutorial / How-toWinCC
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

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.

Target versions: TIA Portal V13 through V20 with WinCC Runtime Professional. Scripts are syntax-compatible across versions; runtime engine differences (RT Professional vs RT Advanced) are explicitly noted in the relevant section.

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

  1. WinCC Professional V13 or later (V15, V16, V17, V18, V19, V20 are confirmed compatible).
  2. WinCC Runtime Professional installed on the target PC, licensed with at least RC 1024 tags or RC 8192 tags depending on scope.
  3. 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.
  4. 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.
  5. VBScript execution enabled in the runtime project (default in RT Professional).
  6. User rights on the RT PC: the runtime service account must have write access to the log directory and execute rights for blat.exe.
Security: Many corporate networks block outbound TCP/25 from SCADA PCs. Coordinate with the IT firewall team and request an explicit allow rule for the SCADA host to the chosen SMTP relay FQDN.

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:

  1. Copy blat.exe, blat.dll, and blat.lib to a stable directory, for example D:\larmer\.
  2. Open a command prompt and install the default profile:
    blat -install smtp.yourdomain.com [email protected] -port 587 -u "smtpuser" -pw "smtppass"
    This stores profile data in the registry under HKLM\Software\Public Domain\Blat.
  3. Send a test message:
    blat -body "WinCC test" -subject "Alarm channel test" -to [email protected]
  4. If the test mail arrives, Blat is operational. If it does not, check blat -debug -log D:\larmer\blat.log output.
Antivirus interaction: Some endpoint protection suites quarantine 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
RT Professional caveat: 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)
Command-line quoting: Always wrap subject, body, and recipient strings in 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

  1. In the TIA project tree, open "HMI alarms" → "Analog alarms".
  2. 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".
  3. In the alarm's "Events" tab, expand "OnCome" (raised).
  4. 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
  5. 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:

  1. Define an internal HMI tag, e.g. AlarmEmailTrigger (Boolean, internal).
  2. On the alarm's OnCome event, configure a "Set tag" system function that sets AlarmEmailTrigger = TRUE.
  3. Bind the email script to a tag change on AlarmEmailTrigger in the "Tag triggers" editor (with edge detection: 0 → 1).
  4. From the same trigger, a second script (file writer) is also invoked by adding both to the trigger's event chain.
Re-arm: The internal trigger tag must be reset to 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

  1. Force the limit violation in the PLC (or use the simulator in TIA).
  2. Watch D:\larmer\TEST-blat.log in real time with Get-Content -Wait (PowerShell) or a tail utility.
  3. 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
  4. Confirm delivery in the recipient mailbox.
  5. 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 -tls on the -install command. For pure TLS on port 465, wrap Blat in stunnel or migrate to Send-MailMessage in 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_TIME will 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.

Back to blog