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.