Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ec69637
Add Posta with PostgreSQL and Redis integration
axies20 Jul 8, 2026
aebb0b4
Add Posta with hosting extensions
axies20 Jul 8, 2026
e89f6a9
Merge branch 'main' into Posta
axies20 Jul 8, 2026
31bac3c
Simplify Posta integration by directly passing database and Redis res…
axies20 Jul 8, 2026
e59b9ae
Add comprehensive tests for `AddPosta` with database and Redis refere…
axies20 Jul 8, 2026
aed268b
Simplify `AddPosta` API by directly passing database and Redis refere…
axies20 Jul 8, 2026
63d6900
Add null checks for database, Redis, and configuration options in `Ad…
axies20 Jul 8, 2026
cc5353d
Add `AddPosta` overloads for chaining PostgreSQL and Redis references…
axies20 Jul 8, 2026
dfc2730
Refactor `AddPosta` tests to include database and Redis dependencies.…
axies20 Jul 8, 2026
83641b7
Enhance `AddPosta` tests with support for overriding `DatabaseUrl` an…
axies20 Jul 8, 2026
423af75
Add overloads to `Set` method in `PostaHostingExtensions` for handlin…
axies20 Jul 8, 2026
fd0be69
Refactor `PostaHostingExtensions` to replace direct environment varia…
axies20 Jul 8, 2026
0115e17
Inject `POSTA_REDIS_PASSWORD` configuration into environment setup fo…
axies20 Jul 8, 2026
9daab45
Refactor README to use Aspire parameters for `PostaOptions` configura…
axies20 Jul 8, 2026
f065540
Refactor `AddPosta` test configuration to use parameterized resources…
axies20 Jul 8, 2026
eb0a90f
Add parameter-based `AddPosta` overload with `PostaOptions` and impro…
axies20 Jul 8, 2026
eb2705a
Refactor `PostaHostingExtensions` to improve environment variable set…
axies20 Jul 8, 2026
74b634e
Refactor `PostaOptions` to replace primitive types with parameterized…
axies20 Jul 8, 2026
c7f31c5
Merge branch 'main' into Posta
axies20 Jul 9, 2026
b777259
Add Posta configuration options and environment variable constants
axies20 Jul 9, 2026
acdadd1
Refactor `AddPosta` tests to improve parameterized resource configura…
axies20 Jul 9, 2026
47e238e
Refactor `AddPosta` and README to enhance parameterized configuration…
axies20 Jul 9, 2026
b6382a3
Refactor `PostaHostingExtensions` to use `PostaEnvironmentVariables` …
axies20 Jul 9, 2026
bd9cdaf
Refactor `PostaOptions` to replace `IResourceBuilder` with primitive …
axies20 Jul 9, 2026
d069e6e
Add extension methods to configure Posta resources for SMTP, OAuth, S…
axies20 Jul 9, 2026
64b542b
Add action-based overloads to configure Posta resources for SMTP, OAu…
axies20 Jul 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CommunityToolkit.Aspire.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@
<Project Path="examples/papercut/CommunityToolkit.Aspire.Hosting.PapercutSmtp.SendMailApi/CommunityToolkit.Aspire.Hosting.PapercutSmtp.SendMailApi.csproj" />
<Project Path="examples/papercut/CommunityToolkit.Aspire.Hosting.PapercutSmtp.ServiceDefaults/CommunityToolkit.Aspire.Hosting.PapercutSmtp.ServiceDefaults.csproj" />
</Folder>
<Folder Name="/examples/posta/">
<Project Path="examples/posta/CommunityToolkit.Aspire.Hosting.Posta.AppHost/CommunityToolkit.Aspire.Hosting.Posta.AppHost.csproj" />
</Folder>
<Folder Name="/examples/perl/">
<Project Path="examples/perl/CpanmApiIntegration.AppHost/CpanmApiIntegration.AppHost.csproj" />
</Folder>
Expand Down Expand Up @@ -269,6 +272,7 @@
<Project Path="src/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.PapercutSmtp/CommunityToolkit.Aspire.Hosting.PapercutSmtp.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.Perl/CommunityToolkit.Aspire.Hosting.Perl.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.Posta/CommunityToolkit.Aspire.Hosting.Posta.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.PowerShell/CommunityToolkit.Aspire.Hosting.PowerShell.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.Python.Extensions/CommunityToolkit.Aspire.Hosting.Python.Extensions.csproj" />
Expand Down Expand Up @@ -344,6 +348,7 @@
<Project Path="tests/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.Tests/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.PapercutSmtp.Tests/CommunityToolkit.Aspire.Hosting.PapercutSmtp.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/CommunityToolkit.Aspire.Hosting.Perl.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.Posta.Tests/CommunityToolkit.Aspire.Hosting.Posta.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.Tests/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.RavenDB.Tests/CommunityToolkit.Aspire.Hosting.RavenDB.Tests.csproj" />
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ This repository contains the source code for the Aspire Community Toolkit, a col
| - **Learn More**: [`Hosting.Bitwarden.SecretManager`][bitwarden-secret-manager-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Hosting.Bitwarden.SecretManager][bitwarden-secret-manager-hosting-shields]][bitwarden-secret-manager-hosting-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.Bitwarden.SecretManager][bitwarden-secret-manager-hosting-shields-preview]][bitwarden-secret-manager-hosting-nuget-preview] | A hosting integration for Bitwarden Secrets Manager projects and managed secrets. |
| - **Learn More**: [`Bitwarden.SecretManager`][bitwarden-secret-manager-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Bitwarden.SecretManager][bitwarden-secret-manager-client-shields]][bitwarden-secret-manager-client-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Bitwarden.SecretManager][bitwarden-secret-manager-client-shields-preview]][bitwarden-secret-manager-client-nuget-preview] | A client integration for authenticating and using the Bitwarden Secrets Manager SDK from Aspire applications. |
| - **Learn More**: [`Hosting.Perl`][perl-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Hosting.Perl][perl-shields]][perl-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.Perl][perl-shields-preview]][perl-nuget-preview] | A hosting integration for Perl scripts and APIs. |
| - **Learn More**: [`Hosting.Posta`][posta-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Hosting.Posta][posta-shields]][posta-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.Posta][posta-shields-preview]][posta-nuget-preview] | An Aspire hosting integration for the [Posta](https://docs.goposta.dev/) self-hosted email delivery platform. |
| - **Learn More**: [`Hosting.Python.Extensions`][python-ext-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Python.Extensions][python-ext-shields]][python-ext-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.Python.Extensions][python-ext-shields-preview]][python-ext-nuget-preview] | An integration that contains some additional extensions for running python applications |
| - **Learn More**: [`Hosting.KurrentDB`][kurrentdb-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Hosting.KurrentDB][kurrentdb-shields]][kurrentdb-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.KurrentDB][kurrentdb-shields-preview]][kurrentdb-nuget-preview] | An Aspire hosting integration leveraging the [KurrentDB](https://www.kurrent.io) container. |
| - **Learn More**: [`KurrentDB`][kurrentdb-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.KurrentDB][kurrentdb-client-shields]][kurrentdb-client-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.KurrentDB][kurrentdb-client-shields-preview]][kurrentdb-client-nuget-preview] | An Aspire client integration for the [KurrentDB](https://github.com/kurrent-io/KurrentDB-Client-Dotnet) package. |
Expand Down Expand Up @@ -178,6 +179,11 @@ This project is supported by the [.NET Foundation](https://dotnetfoundation.org)
[perl-nuget]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Perl/
[perl-shields-preview]: https://img.shields.io/nuget/vpre/CommunityToolkit.Aspire.Hosting.Perl?label=nuget%20(preview)
[perl-nuget-preview]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Perl/absoluteLatest
[posta-integration-docs]: ./src/CommunityToolkit.Aspire.Hosting.Posta/README.md
[posta-shields]: https://img.shields.io/nuget/v/CommunityToolkit.Aspire.Hosting.Posta
[posta-nuget]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Posta/
[posta-shields-preview]: https://img.shields.io/nuget/vpre/CommunityToolkit.Aspire.Hosting.Posta?label=nuget%20(preview)
[posta-nuget-preview]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Posta/absoluteLatest
[python-ext-integration-docs]: https://learn.microsoft.com/dotnet/aspire/community-toolkit/hosting-python-extensions
[python-ext-shields]: https://img.shields.io/nuget/v/CommunityToolkit.Aspire.Hosting.Python.Extensions
[python-ext-nuget]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Python.Extensions/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Aspire.AppHost.Sdk/13.4.3">

<PropertyGroup>
<OutputType>Exe</OutputType>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting.PostgreSQL" />
<PackageReference Include="Aspire.Hosting.Redis" />
<PackageReference Include="MessagePack" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\CommunityToolkit.Aspire.Hosting.Posta\CommunityToolkit.Aspire.Hosting.Posta.csproj" IsAspireProjectResource="false" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
var builder = DistributedApplication.CreateBuilder(args);

var postgresPassword = builder.AddParameter("postgres-password", "posta");
var postgres = builder.AddPostgres("postgres", password: postgresPassword);
var database = postgres.AddDatabase("posta-db", "posta");
var redis = builder.AddRedis("redis");

builder.AddPosta("posta", database, redis);

builder.Build().Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:18131;http://localhost:12049",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:32487",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:12811"
}
},
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:15184",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19198",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:21263"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Description>An Aspire hosting integration for Posta.</Description>
<AdditionalPackageTags>hosting posta email smtp delivery</AdditionalPackageTags>
<DisablePackageBaselineValidation>true</DisablePackageBaselineValidation>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting" />
<PackageReference Include="Aspire.Hosting.PostgreSQL" />
<PackageReference Include="Aspire.Hosting.Redis" />
<PackageReference Include="MessagePack" />
</ItemGroup>

<ItemGroup>
<InternalsVisibleTo Include="CommunityToolkit.Aspire.Hosting.Posta.Tests" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace CommunityToolkit.Aspire.Hosting.Posta;

internal static class PostaContainerImageTags
{
/// <remarks>docker.io</remarks>
public const string Registry = "docker.io";

/// <remarks>jkaninda/posta</remarks>
public const string Image = "jkaninda/posta";

/// <remarks>0.11.0</remarks>
public const string Tag = "0.11.0";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Aspire.Hosting.ApplicationModel;

namespace CommunityToolkit.Aspire.Hosting.Posta;

/// <summary>
/// Parameter-based configuration options for Posta email verification.
/// </summary>
public sealed class PostaEmailVerificationOptions
{
/// <summary>
/// Gets or sets whether users must verify their email address before sign-in.
/// </summary>
public IResourceBuilder<ParameterResource>? Required { get; set; }

/// <summary>
/// Gets or sets whether permanently rejected recipients are added to the suppression list.
/// </summary>
public IResourceBuilder<ParameterResource>? AutoSuppressOnReject { get; set; }

/// <summary>
/// Gets or sets whether the email verification endpoint is enabled.
/// </summary>
public IResourceBuilder<ParameterResource>? Enabled { get; set; }

/// <summary>
/// Gets or sets how long address-level verification results are cached, in hours.
/// </summary>
public IResourceBuilder<ParameterResource>? CacheTtlHours { get; set; }

/// <summary>
/// Gets or sets how long domain MX lookups are cached, in hours.
/// </summary>
public IResourceBuilder<ParameterResource>? MxCacheTtlHours { get; set; }

/// <summary>
/// Gets or sets the per-user hourly cap on verification requests.
/// </summary>
public IResourceBuilder<ParameterResource>? RateHourly { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
namespace CommunityToolkit.Aspire.Hosting.Posta;

internal static class PostaEnvironmentVariables
{
public const string Port = "POSTA_PORT";
public const string DbUrl = "POSTA_DB_URL";
public const string DbHost = "POSTA_DB_HOST";
public const string DbPort = "POSTA_DB_PORT";
public const string DbUser = "POSTA_DB_USER";
public const string DbPassword = "POSTA_DB_PASSWORD";
public const string DbName = "POSTA_DB_NAME";
public const string DbSslMode = "POSTA_DB_SSL_MODE";
public const string RedisAddress = "POSTA_REDIS_ADDR";
public const string RedisPassword = "POSTA_REDIS_PASSWORD";
public const string JwtSecret = "POSTA_JWT_SECRET";
public const string AdminEmail = "POSTA_ADMIN_EMAIL";
public const string AdminPassword = "POSTA_ADMIN_PASSWORD";
public const string Environment = "POSTA_ENV";
public const string DevMode = "POSTA_DEV_MODE";
public const string AuthRateLimitEnabled = "POSTA_AUTH_RATE_LIMIT_ENABLED";
public const string RateLimitHourly = "POSTA_RATE_LIMIT_HOURLY";
public const string RateLimitDaily = "POSTA_RATE_LIMIT_DAILY";
public const string OpenApiDocs = "POSTA_OPENAPI_DOCS";
public const string MetricsEnabled = "POSTA_METRICS_ENABLED";
public const string WebDir = "POSTA_WEB_DIR";
public const string WebUrl = "POSTA_WEB_URL";
public const string ApiUrl = "POSTA_API_URL";
public const string CorsOrigins = "POSTA_CORS_ORIGINS";
public const string EmbeddedWorker = "POSTA_EMBEDDED_WORKER";
public const string WorkerConcurrency = "POSTA_WORKER_CONCURRENCY";
public const string WorkerMaxRetries = "POSTA_WORKER_MAX_RETRIES";
public const string WebhookMaxRetries = "POSTA_WEBHOOK_MAX_RETRIES";
public const string WebhookTimeoutSeconds = "POSTA_WEBHOOK_TIMEOUT_SECS";
public const string WebhookProxyUrl = "POSTA_WEBHOOK_PROXY_URL";
public const string GoogleOAuthClientId = "POSTA_GOOGLE_OAUTH_CLIENT_ID";
public const string GoogleOAuthClientSecret = "POSTA_GOOGLE_OAUTH_CLIENT_SECRET";
public const string OAuthCallbackUrl = "POSTA_OAUTH_CALLBACK_URL";
public const string BlobProvider = "POSTA_BLOB_PROVIDER";
public const string BlobS3Endpoint = "POSTA_BLOB_S3_ENDPOINT";
public const string BlobS3Region = "POSTA_BLOB_S3_REGION";
public const string BlobS3Bucket = "POSTA_BLOB_S3_BUCKET";
public const string BlobS3AccessKey = "POSTA_BLOB_S3_ACCESS_KEY";
public const string BlobS3SecretKey = "POSTA_BLOB_S3_SECRET_KEY";
public const string BlobS3UseSsl = "POSTA_BLOB_S3_USE_SSL";
public const string BlobS3PathStyle = "POSTA_BLOB_S3_PATH_STYLE";
public const string BlobFileSystemPath = "POSTA_BLOB_FS_PATH";
public const string EncryptionKey = "POSTA_ENCRYPTION_KEY";
public const string SystemSmtpHost = "POSTA_SYSTEM_SMTP_HOST";
public const string SystemSmtpPort = "POSTA_SYSTEM_SMTP_PORT";
public const string SystemSmtpUsername = "POSTA_SYSTEM_SMTP_USERNAME";
public const string SystemSmtpPassword = "POSTA_SYSTEM_SMTP_PASSWORD";
public const string SystemSmtpFrom = "POSTA_SYSTEM_SMTP_FROM";
public const string SystemSmtpEncryption = "POSTA_SYSTEM_SMTP_ENCRYPTION";
public const string InboundEnabled = "POSTA_INBOUND_ENABLED";
public const string InboundSmtpHost = "POSTA_INBOUND_SMTP_HOST";
public const string InboundSmtpPort = "POSTA_INBOUND_SMTP_PORT";
public const string InboundHostname = "POSTA_INBOUND_HOSTNAME";
public const string InboundMaxMessageSize = "POSTA_INBOUND_MAX_MESSAGE_SIZE";
public const string InboundMaxAttachSize = "POSTA_INBOUND_MAX_ATTACH_SIZE";
public const string InboundWebhookSecret = "POSTA_INBOUND_WEBHOOK_SECRET";
public const string InboundTlsMode = "POSTA_INBOUND_TLS_MODE";
public const string InboundTlsCertFile = "POSTA_INBOUND_TLS_CERT_FILE";
public const string InboundTlsKeyFile = "POSTA_INBOUND_TLS_KEY_FILE";
public const string InboundSmtpRateLimit = "POSTA_INBOUND_SMTP_RATE_LIMIT";
public const string InboundSmtpRateWindow = "POSTA_INBOUND_SMTP_RATE_WINDOW";
public const string EmailVerificationRequired = "POSTA_EMAIL_VERIFICATION_REQUIRED";
public const string AutoSuppressOnReject = "POSTA_AUTO_SUPPRESS_ON_REJECT";
public const string EmailVerifyEnabled = "POSTA_EMAIL_VERIFY_ENABLED";
public const string EmailVerifyCacheTtlHours = "POSTA_EMAIL_VERIFY_CACHE_TTL_HOURS";
public const string EmailVerifyMxCacheTtlHours = "POSTA_EMAIL_VERIFY_MX_CACHE_TTL_HOURS";
public const string EmailVerifyRateHourly = "POSTA_EMAIL_VERIFY_RATE_HOURLY";
public const string AllowDowngrade = "POSTA_ALLOW_DOWNGRADE";
public const string PlanEnforcement = "POSTA_PLAN_ENFORCEMENT";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Aspire.Hosting.ApplicationModel;

namespace CommunityToolkit.Aspire.Hosting.Posta;

/// <summary>
/// Parameter-based configuration options for Posta Google OAuth login.
/// </summary>
public sealed class PostaGoogleOAuthOptions
{
/// <summary>
/// Gets or sets the Google OAuth client ID for SSO login.
/// </summary>
public IResourceBuilder<ParameterResource>? ClientId { get; set; }

/// <summary>
/// Gets or sets the Google OAuth client secret for SSO login.
/// </summary>
public IResourceBuilder<ParameterResource>? ClientSecret { get; set; }

/// <summary>
/// Gets or sets the OAuth callback base URL.
/// </summary>
public IResourceBuilder<ParameterResource>? CallbackUrl { get; set; }
}
Loading
Loading