---
title: Log exception and send notification email
summary: Capture an exception, persist it through the active sink, and send an HTML notification email about it.
status: draft
owner: SAIF Documentation
last_reviewed: 2026-07-30
library: SAIF.Framework.Logging
reference_type: package
operation_id: LOG-OP-003
trigger: Caller invokes clsLogError.CreateErrorWithEmail(...)
---

# Log exception and send notification email

This operation layers a second side effect — an outbound HTML email — on top of the standard error-logging path. It reuses the same context-capture, ViewState-suppression, and persistence logic as `CreateError(...)`, then composes a notification email whose sender address is always derived from the captured username rather than any caller-supplied value.

| Field | Value |
| --- | --- |
| **Operation ID** | LOG-OP-003 |
| **Trigger** | Caller invokes `clsLogError.CreateErrorWithEmail(...)`. |
| **Inputs** | Recipient address, `Exception`, and optional state objects. |
| **Outputs** | `Boolean`; `False` only when ViewState suppression matches, otherwise `True` even if either the log write or the email send fails. |
| **Primary components** | `clsLogError.CreateErrorWithEmail`, `clsLogError.WriteMessage`, `SAIFMail.clsSAIFMessage.SendMail` |
| **Entry point** | `SAIF.Framework.Logging/clsLogError.vb` |

## Steps

1. Reuse the same payload-construction path as `CreateError(...)`: create `clsLogError`, capture machine, application, page, environment, and user context, flatten any nested exceptions, and serialize whatever state objects the caller supplied ([BR-005](../business-rules.md#br-005-logging-failures-must-never-raise-exceptions-to-the-caller)).

   > **Origin**: The current-user resolution inside step 1 delegates to `clsSecurityPrincipal`, documented in [Principal identity initialization](../../saif-framework-security/operations/principal-identity-initialization.md) (`SAIF.Framework.Security`).
2. Run `SuppressLogging()` and return `False` immediately when the formatted exception text matches either ViewState suppression signature — no email is composed for a suppressed error ([BR-004](../business-rules.md#br-004-aspnet-viewstate-errors-are-never-logged)).
3. Persist the error through `WriteMessage()` before attempting the email.
   - If no file sink is active, resolve `loggingServiceUrl`, map the payload into `wsLogging.ErrorInfoStruct`, call `WriteError(...)`, dispose the proxy, and swallow any resulting exception ([BR-005](../business-rules.md#br-005-logging-failures-must-never-raise-exceptions-to-the-caller)).
   - Otherwise append `ErrorInfoStruct.ToCSVString()` to the open file writer and flush it.

   > **Origin**: The `loggingServiceUrl` lookup in step 3 delegates to Environment API configuration retrieval, summarized in [Retrieve a configuration setting](../../saif-framework-security-environmentapi/operations/retrieve-configuration-setting.md) (`SAIF.Framework.Security.EnvironmentApi`).
4. Build and dispatch the notification email.
   - Instantiate `New SAIF.Framework.Mail.SAIFMail.clsSAIFMessage`.
   - Resolve `legacyMailServiceUrl`, append `?op=SendMail`, and assign the resulting URL to the proxy before invoking the mail operation.
   - Format the subject with `MSGSUBJECT`, substituting the captured application name, machine name, and environment.
   - Call `SendMail(inSendTo, ErrorInfo.Username & "@SAIF.COM", subject, ErrorInfo.ToHTMLString())`, so the sender address always resolves to the `@SAIF.COM` domain regardless of the recipient ([BR-006](../business-rules.md#br-006-email-error-notification-always-sent-to-a-fixed-corporate-email-domain)).

   > **Origin**: The endpoint lookup in step 4.2 delegates to Environment API configuration retrieval, and the synchronous SOAP invocation in step 4.4 follows the mail-send flow summarized in [Send email with body](../../saif-framework-mail/operations/send-email-with-body.md) (`SAIF.Framework.Mail`).
5. Swallow any exception raised anywhere in the combined log-write or email-send flow, then return `True`, so a notification-delivery problem never breaks the caller's original work ([BR-005](../business-rules.md#br-005-logging-failures-must-never-raise-exceptions-to-the-caller)).

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([CreateErrorWithEmail request]) --> Build[Build ErrorInfoStruct]
	Build --> Suppress{ViewState signature found?}
	Suppress -->|Yes| EndDrop([Return False])
	Suppress -->|No| Persist[Write error through active sink]
	Persist --> Mail[Resolve legacyMailServiceUrl and send HTML email]
	Mail --> EndOk([Return True])
```

## Failure and edge-case behavior

- ViewState-noise exceptions are discarded before either the sink write or the email attempt starts, so no notification email is ever sent for suppressed errors ([BR-004](../business-rules.md#br-004-aspnet-viewstate-errors-are-never-logged)).
- The sender address is always `Username + "@SAIF.COM"`, even for users whose real address lives in a different domain ([BR-006](../business-rules.md#br-006-email-error-notification-always-sent-to-a-fixed-corporate-email-domain)).
- The method still returns `True` when the mail endpoint is unreachable, because the outer catch absorbs notification failures along with logging failures ([BR-005](../business-rules.md#br-005-logging-failures-must-never-raise-exceptions-to-the-caller)).

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [Configuration](../configuration.md)

## Sources
- `SAIF.Framework.Logging/clsLogError.vb`
- `SAIF.Framework.Logging/ErrorInfoStruct.vb`
- `SAIF.Framework.Logging/clsLogCommon.vb`
- `SAIF.Framework.Security/clsSecurityPrincipal.vb`
- `SAIF.Framework.Security.EnvironmentApi/Services.Common/EnvironmentServiceBase.cs`
- `SAIF.Framework.Security.EnvironmentApi/Services.Common/EnvironmentConfigKeys.cs`
- `SAIF.Framework.Mail/Web References/SAIFMail/Reference.vb`
