---
title: CertificateDistributionService
summary: API reference for CertificateDistributionService.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-09-24
library: SAIF.Services
reference_type: package
---

# CertificateDistributionService

Implements `ICertificateDistributionService`, coordinating the end-to-end distribution of a generated certificate document — rendering it via `Core.Contracts.Policies.Certificates.Document.IDocumentService`, emailing it through `IEmailService`/`CertificateEmailer`, faxing it through `IFaxService`, and queuing an imaged copy through `IDocumentService.ImagingService` — using `ICertificateInformationService` for policy lookups and `ICertificatePreferenceService` for the policyholder's preferred delivery method.

## Purpose
- Distributes a certificate to email and fax stakeholders, and additionally sends a policyholder copy when the distribution point is `New`.
- Determines and applies the policyholder's preferred delivery method (email or fax) for the policyholder's own copy of a newly issued certificate.
- Produces preview streams of a certificate (standard and policyholder-copy variants) without sending them.
- Queues a certificate document for imaging/archival, tagging it as a bid certificate, an "other states" certificate, or a named policyholder-copy comment as appropriate.

## Context
- Namespace: `SAIF.Services.Policies.Certificates`
- Assembly/package: `SAIF.Services` (packaged inside the `SAIF.SAIFCode.Core` NuGet package).

## Public members
| Member | Signature | Purpose |
| --- | --- | --- |
| CertificateDistributionService (constructor) | `public CertificateDistributionService(ICertificatePreferenceService preferenceService, Core.Contracts.Policies.Certificates.Document.IDocumentService certDocumentService, ICertificateInformationService certificateInformationService, IEmailService emailService, IFaxService faxService, IDocumentService utilDocumentService)` | Wires the preference, certificate-document, certificate-information, email, fax, and general document/imaging service collaborators (each null-checked via `Enforce.ArgumentNotNull`) used by every distribution operation. |
| DistributeCertificate | `public void DistributeCertificate(Certificate certificate, DistributionOptions distributionOptions)` | Renders the certificate document stream via `certDocumentService.GetCertificateDocumentStream` and delegates to `DistributeCertificateStream` for the actual email/fax/policyholder-copy distribution. |
| DistributeCertificateStream | `public void DistributeCertificateStream(Certificate certificate, Stream certificateStream, DistributionOptions distributionOptions)` | Looks up the policy, splits `distributionOptions.Recipients` into email and fax recipients, sends the certificate stream to each group via `SendEmailstoStakeHolders`/`SendFaxestoStakeHolders`, and, when `distributionOptions.DistributionPoint` is `CertificateDistributionPoint.New`, additionally renders and sends a policyholder copy via `DistributePolicyHolderCopy`. |
| PreviewCertificate | `public Stream PreviewCertificate(Certificate certificate)` | Returns the rendered certificate document stream without distributing it. |
| PreviewCertificatePolicyHolderCopy | `public Stream PreviewCertificatePolicyHolderCopy(Certificate certificate)` | Returns the rendered policyholder-copy variant of the certificate document stream without distributing it. |
| DistributePolicyHolderCopy | `public void DistributePolicyHolderCopy(Certificate certificate, CertificatePreference preference, Stream stream)` | Skips renewal certificates; otherwise images the stream as a policyholder copy, then sends it by email or fax according to `preference.DeliveryMethod`, using a subject that includes the certificate ID and holder/bid name. |
| SendEmailstoStakeHolders | `public void SendEmailstoStakeHolders(Certificate certificate, IEnumerable<string> emailAddressList, Stream stream, Policy policy, string emailSubject = "")` | Returns immediately if there are no email addresses; otherwise builds a subject line (the supplied one, or a default including certificate ID and policy name) and delegates the actual send to `CertificateEmailer.SendEmailstoStakeHolders`. |
| SendFaxestoStakeHolders | `public void SendFaxestoStakeHolders(IEnumerable<PhoneNumber> faxNumbers, Stream stream, Certificate certificate, Policy policy)` | Returns immediately if there are no fax numbers; otherwise builds a `FaxConfig` from the stream bytes, adds one recipient per fax number (prefixing the numeric value with `"91"`) named per the certificate, and sends it via `faxService.SendFax`. |
| ImageCertificate | `public long ImageCertificate(Certificate certificate, Stream certificateStream, Boolean isPolicyholderCopy, string createUser)` | Builds an imaging comment ("Bid Certificate", the certificate holder's name, or that name suffixed with "(Policyholder copy)"), determines the "other states" flag, requests an `ImageConfig` from `certDocumentService`, and queues the document bytes for imaging via `utilDocumentService.ImagingService.QueueImage`, returning the resulting image ID. |

## Behavioral notes
- `DistributeCertificateStream` always attempts both email and fax distribution (each a no-op when its recipient list is empty), and only triggers the policyholder-copy path for `CertificateDistributionPoint.New` distributions.
- `DistributePolicyHolderCopy` is a no-op for renewal certificates (`certificate.IsRenewalCertificate`), and only images/sends the policyholder copy for `Email` or `Fax` delivery methods on the resolved `CertificatePreference`; other delivery methods result in no action.
- Subject lines are built from module-level format constants (`POLICYHOLDER_SUBJECT_LINE`, `STAKEHOLDER_SUBJECT_LINE`) that embed the certificate ID and either the certificate holder/bid name or the policy name.
- `ImageCertificate` and `SendFaxestoStakeHolders` both convert the certificate stream to a byte array via `Stream.ToByteArray()` before handing it to the imaging or fax subsystem.
- Actual stakeholder email sending is delegated to the static `CertificateEmailer.SendEmailstoStakeHolders` helper rather than implemented locally.

## Constraints and usage notes
- All six constructor collaborators are null-checked via `Enforce.ArgumentNotNull`, but most public method parameters (certificate, stream, policy, etc.) are not, per the `CA1062` suppressions attached to several methods.*
- Callers must ensure a given `Stream` argument is positioned/rewound appropriately before invoking distribution methods a second time, since `SendEmailstoStakeHolders`/`CertificateEmailer` rely on stream position management across multiple recipients.*

> **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.

## Sources
- `Services/SAIF.Services/Policies/Certificates/CertificateDistributionService.cs`
