Skip to content

Report Delivery ​

GrydReports supports automatic delivery of generated reports through multiple channels: Email, Webhook, and Storage. Delivery is configured per-request or per-schedule.

Delivery Methods ​

MethodEnumDescription
DownloadDeliveryMethod.Download (1)Default — file available via download endpoint
EmailDeliveryMethod.Email (2)Send report as email attachment
StorageDeliveryMethod.Storage (3)Copy to a target path (shared drive, S3, etc.)
WebhookDeliveryMethod.Webhook (4)POST to an external URL with report metadata

DeliveryOptions ​

csharp
public class DeliveryOptions
{
    public DeliveryMethod Method { get; set; }

    // Email
    public List<string>? Recipients { get; set; }
    public List<string>? CcRecipients { get; set; }
    public string? EmailSubject { get; set; }
    public string? EmailBody { get; set; }

    // Webhook
    public string? WebhookUrl { get; set; }
    public Dictionary<string, string>? WebhookHeaders { get; set; }

    // Storage
    public string? TargetPath { get; set; }
}

Email Delivery ​

Send reports as email attachments:

json
{
  "delivery": {
    "method": 2,
    "recipients": ["manager@company.com", "director@company.com"],
    "ccRecipients": ["archive@company.com"],
    "emailSubject": "Monthly Financial Report - February 2026",
    "emailBody": "Please find the attached monthly financial report."
  }
}

Configuration ​

csharp
builder.Services.ConfigureGrydReportsDelivery(opts =>
{
    opts.EmailFrom = "reports@company.com";
    opts.EmailFromName = "Report System";
    opts.SmtpHost = "smtp.company.com";
    opts.SmtpPort = 587;
    opts.SmtpUseSsl = true;
    opts.SmtpUsername = "smtp-user";
    opts.SmtpPassword = "smtp-password";
});

appsettings.json ​

json
{
  "GrydReports": {
    "EmailDelivery": {
      "EmailFrom": "reports@company.com",
      "EmailFromName": "Report System",
      "SmtpHost": "smtp.company.com",
      "SmtpPort": 587,
      "SmtpUseSsl": true,
      "SmtpUsername": "smtp-user",
      "SmtpPassword": "smtp-password"
    }
  }
}

Webhook Delivery ​

POST report metadata to an external endpoint:

json
{
  "delivery": {
    "method": 4,
    "webhookUrl": "https://api.company.com/webhooks/reports",
    "webhookHeaders": {
      "Authorization": "Bearer token-123",
      "X-Correlation-Id": "req-456"
    }
  }
}

The webhook receives a POST with the following payload:

json
{
  "reportId": "f47ac10b-...",
  "templateId": "monthly-sales",
  "format": "Pdf",
  "status": "Completed",
  "fileName": "monthly-sales-2026-02.pdf",
  "fileSizeBytes": 245760,
  "downloadUrl": "/api/v1/reports/f47ac10b-.../download",
  "generatedAt": "2026-02-19T10:30:00Z"
}

Webhook Configuration ​

csharp
builder.Services.ConfigureGrydReportsDelivery(opts =>
{
    opts.WebhookTimeout = TimeSpan.FromSeconds(30);
    opts.WebhookRetryCount = 3;
});

Storage Delivery ​

Copy the generated file to a shared path:

json
{
  "delivery": {
    "method": 3,
    "targetPath": "/shared/reports/finance/2026/"
  }
}

IReportDelivery Interface ​

Each delivery method is implemented as an IReportDelivery:

csharp
public interface IReportDelivery
{
    DeliveryMethod Method { get; }
    Task<Result> DeliverAsync(
        ReportOutput output,
        DeliveryOptions options,
        CancellationToken ct = default);
}

Built-in Implementations ​

ClassMethodDescription
EmailReportDeliveryEmailSMTP-based email with attachment
WebhookReportDeliveryWebhookHTTP POST with report metadata

Custom Delivery Channel ​

Implement IReportDelivery to add your own channel (e.g., Slack, Teams, S3):

csharp
public class SlackReportDelivery : IReportDelivery
{
    public DeliveryMethod Method => DeliveryMethod.Webhook;

    private readonly ISlackClient _slack;

    public SlackReportDelivery(ISlackClient slack) => _slack = slack;

    public async Task<Result> DeliverAsync(
        ReportOutput output, DeliveryOptions options, CancellationToken ct)
    {
        var channel = options.WebhookUrl!; // Use webhook URL as channel

        await _slack.UploadFileAsync(
            channel: channel,
            stream: output.Content,
            fileName: output.FileName,
            message: $"📊 Report ready: {output.FileName}",
            cancellationToken: ct);

        return Result.Success();
    }
}

// Register
builder.Services.AddScoped<IReportDelivery, SlackReportDelivery>();

Delivery with Scheduling ​

Combine delivery with scheduling for fully automated workflows:

csharp
await mediator.Send(new CreateReportScheduleCommand(
    TemplateId: "daily-kpis",
    Name: "Daily KPI Report",
    CronExpression: "0 7 * * MON-FRI",
    Format: ReportFormat.Pdf,
    Delivery: new DeliveryOptions
    {
        Method = DeliveryMethod.Email,
        Recipients = ["leadership@company.com"],
        EmailSubject = "Daily KPIs - {date}",
        EmailBody = "Good morning! Here are today's KPI metrics."
    }
));

Delivery with Async Generation ​

Include delivery in on-demand async generation:

bash
POST /api/v1/reports/generate-async
{
  "templateId": "audit-export",
  "format": 3,
  "delivery": {
    "method": 2,
    "recipients": ["compliance@company.com"]
  }
}

The report is generated in background and automatically delivered when complete.

Multiple Delivery Channels

All registered IReportDelivery implementations are available. The system selects the correct one based on DeliveryOptions.Method. You can register multiple implementations for different channels.

Released under the MIT License.