---
title: Read a file into bytes
summary: Opens a file, copies its contents into a byte array, and returns that array to the attachment-sending pipeline.
status: draft
owner: SAIF Documentation Generator
last_reviewed: 2026-07-30
library: SAIF.Framework.Mail
reference_type: package
operation_id: MAIL-OP-005
trigger: Attachment-sending code calls `GetFileAsBytes(inPath)`.
---

# Read a file into bytes

This internal helper materializes a file on disk as a `Byte()` array so the file-path overload of `SendMailWithAttachment` can pass it to the SOAP proxy. It guarantees the underlying file handle is released whether or not the read succeeds, but it does so at the cost of resetting the stack trace of any exception it re-throws.

| Field | Value |
| --- | --- |
| **Operation ID** | MAIL-OP-005 |
| **Trigger** | Attachment-sending code calls `GetFileAsBytes(inPath)`. |
| **Inputs** | `inPath`. |
| **Outputs** | A `Byte()` payload, or a propagated exception. |
| **Primary components** | `Mail.GetFileAsBytes`, `System.IO.FileStream` |
| **Entry point** | `SAIF.Framework.Mail\MailServices.vb` |

## Steps

1. Initialize the local `FS` variable to `Nothing` before entering the `Try...Catch...Finally` block, so `Finally` has a defined reference to inspect even if opening the file fails.
2. Inside `Try`, open the file with `New IO.FileStream(inPath, FileMode.Open)`.
3. Allocate `Dim FileBytes(CInt(FS.Length)) As Byte` and read `FS.Length` bytes from the stream into that array.
4. Return the populated array to the caller.
5. If any exception occurs while the file is open or being read, re-throw it with `Throw ex` ([BR-004](../business-rules.md#br-004-file-handles-are-always-released-but-the-original-exceptions-stack-trace-is-reset)).
6. In `Finally`, call `FS.Close()` to release the file handle regardless of whether step 3 succeeded or step 5 raised an exception ([BR-004](../business-rules.md#br-004-file-handles-are-always-released-but-the-original-exceptions-stack-trace-is-reset)).

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
    Start([GetFileAsBytes call]) --> Open[Open FileStream]
    Open --> Read[Allocate byte array and read file]
    Read --> ReturnBytes[Return byte array]
    Open -->|Exception| ThrowErr[Re-throw exception]
    Read --> Finally[Close FileStream in Finally]
    ThrowErr --> Finally
    Finally --> End([Caller continues or receives exception])
```

## Failure and edge-case behavior

- Re-throwing with `Throw ex` rather than a bare `Throw` resets the exception's stack trace, so the caller sees where the re-throw happened rather than where the original error occurred.*
- `FS.Close()` runs unconditionally in `Finally`; if the `FileStream` constructor itself fails before `FS` is assigned a usable instance, this cleanup step can raise a `NullReferenceException` that masks the original error.*
- Because VB array declarations specify an inclusive upper bound, `Dim FileBytes(CInt(FS.Length)) As Byte` allocates one more element than the file's byte count, leaving a trailing zero byte in the returned array.

> **Note:** Statements marked with * were inferred from code structure, naming conventions, or
> contextual evidence where direct confirmation was not available in source artifacts. Statements
> marked with ** could not be confirmed; treat as unknown until verified.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Overview](../overview.md)
- [Architecture](../architecture.md)
- [Dependencies](../dependencies.md)
- [Business rules](../business-rules.md)
- [Configuration](../configuration.md)
- [API reference](../api/index.md)

## Sources
- SAIF.Framework.Mail\MailServices.vb
