Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
22 changes: 21 additions & 1 deletion src/Resend.Webhooks/DomainEventData.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Text.Json.Serialization;
using System.Text.Json.Serialization;

namespace Resend.Webhooks;

Expand Down Expand Up @@ -34,6 +34,26 @@ public class DomainEventData : IWebhookData
[JsonPropertyName( "region" )]
public DeliveryRegion Region { get; set; }

/// <summary />
[JsonPropertyName( "open_tracking" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public bool? OpenTracking { get; set; }

/// <summary />
[JsonPropertyName( "click_tracking" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public bool? ClickTracking { get; set; }

/// <summary />
[JsonPropertyName( "tracking_subdomain" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public string? TrackingSubdomain { get; set; }

/// <summary />
[JsonPropertyName( "capabilities" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public DomainCapabilities? Capabilities { get; set; }

/// <summary>
/// DNS records used for domain validation.
/// </summary>
Expand Down
30 changes: 29 additions & 1 deletion src/Resend/Domain.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Text.Json.Serialization;
using System.Text.Json.Serialization;

namespace Resend;

Expand Down Expand Up @@ -36,6 +36,34 @@ public class Domain
[JsonPropertyName( "region" )]
public DeliveryRegion Region { get; set; }

/// <summary>
/// Whether open tracking is enabled for this domain.
/// </summary>
[JsonPropertyName( "open_tracking" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public bool? OpenTracking { get; set; }

/// <summary>
/// Whether click tracking is enabled for this domain.
/// </summary>
[JsonPropertyName( "click_tracking" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public bool? ClickTracking { get; set; }

/// <summary>
/// Subdomain used for click and open tracking URLs (for example, <c>links</c> for <c>links.example.com</c>).
/// </summary>
[JsonPropertyName( "tracking_subdomain" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public string? TrackingSubdomain { get; set; }

/// <summary>
/// Whether this domain can send and receive email.
/// </summary>
[JsonPropertyName( "capabilities" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public DomainCapabilities? Capabilities { get; set; }

/// <summary>
/// DNS records used for domain validation.
/// </summary>
Expand Down
37 changes: 36 additions & 1 deletion src/Resend/DomainAddData.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Text.Json.Serialization;
using System.Text.Json.Serialization;

namespace Resend;

Expand Down Expand Up @@ -29,4 +29,39 @@ public class DomainAddData
[JsonPropertyName( "custom_return_path" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public string? CustomReturnPath { get; set; }

/// <summary>
/// TLS mode for outbound mail from this domain.
/// </summary>
[JsonPropertyName( "tls" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public TlsMode? TlsMode { get; set; }

/// <summary>
/// Configure sending and receiving for this domain. At least one capability must remain enabled.
/// </summary>
[JsonPropertyName( "capabilities" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public DomainCapabilities? Capabilities { get; set; }

/// <summary>
/// Track the open rate of each email.
/// </summary>
[JsonPropertyName( "open_tracking" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public bool? OpenTracking { get; set; }

/// <summary>
/// Track clicks within the body of each HTML email.
/// </summary>
[JsonPropertyName( "click_tracking" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public bool? ClickTracking { get; set; }

/// <summary>
/// Subdomain for click and open tracking (for example, <c>links</c> for <c>links.example.com</c>).
/// </summary>
[JsonPropertyName( "tracking_subdomain" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public string? TrackingSubdomain { get; set; }
}
23 changes: 23 additions & 0 deletions src/Resend/DomainCapabilities.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Text.Json.Serialization;

namespace Resend;

/// <summary>
/// Sending and receiving capabilities for a domain.
/// </summary>
public class DomainCapabilities
{
/// <summary>
/// Whether sending is enabled for this domain. Example values: <c>enabled</c>, <c>disabled</c>.
/// </summary>
[JsonPropertyName( "sending" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public string? Sending { get; set; }

/// <summary>
/// Whether receiving is enabled for this domain. Example values: <c>enabled</c>, <c>disabled</c>.
/// </summary>
[JsonPropertyName( "receiving" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public string? Receiving { get; set; }
}
4 changes: 2 additions & 2 deletions src/Resend/DomainRecord.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Text.Json.Serialization;
using System.Text.Json.Serialization;

namespace Resend;

Expand All @@ -7,7 +7,7 @@ public class DomainRecord
{
/// <summary />
/// <remarks>
/// Example values: SPF, DKIM.
/// Example values: SPF, DKIM, Receiving, Tracking.
/// </remarks>
[JsonPropertyName( "record" )]
public string Record { get; set; } = default!;
Expand Down
20 changes: 19 additions & 1 deletion src/Resend/DomainUpdateData.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Text.Json.Serialization;
using System.Text.Json.Serialization;

namespace Resend;

Expand All @@ -23,6 +23,24 @@ public class DomainUpdateData
[JsonPropertyName( "tls" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public TlsMode? TlsMode { get; set; }

/// <summary>
/// Configure sending and receiving for this domain. At least one capability must remain enabled.
/// </summary>
[JsonPropertyName( "capabilities" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public DomainCapabilities? Capabilities { get; set; }

/// <summary>
/// Subdomain for click and open tracking (for example, <c>links</c> for <c>links.example.com</c>).
/// </summary>
/// <remarks>
/// This value can only be set after it has been specified, never cleared. After changing the tracking
/// subdomain, verify DNS again; until then, the previous value may still be used for tracked links.
/// </remarks>
[JsonPropertyName( "tracking_subdomain" )]
[JsonIgnore( Condition = JsonIgnoreCondition.WhenWritingNull )]
public string? TrackingSubdomain { get; set; }
}


Expand Down
113 changes: 113 additions & 0 deletions tests/Resend.Tests/DomainTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
using System.Net.Http.Json;
using System.Text.Json;

namespace Resend.Tests;

/// <summary />
public class DomainTests
{
/// <summary />
[Fact]
public void DomainAddData_serializes_capabilities_and_tls()
{
var data = new DomainAddData()
{
DomainName = "example.com",
TlsMode = TlsMode.Enforced,
Capabilities = new DomainCapabilities()
{
Sending = "enabled",
Receiving = "disabled",
},
};

var json = JsonSerializer.Serialize( data );
Assert.Contains( "\"tls\":\"enforced\"", json );
Assert.Contains( "\"capabilities\"", json );
Assert.Contains( "\"sending\":\"enabled\"", json );
}


/// <summary />
[Fact]
public void DomainAddData_serializes_tracking_fields()
{
var data = new DomainAddData()
{
DomainName = "example.com",
ClickTracking = true,
TrackingSubdomain = "links",
};

var json = JsonSerializer.Serialize( data );
Assert.Contains( "\"click_tracking\":true", json );
Assert.Contains( "\"tracking_subdomain\":\"links\"", json );
Assert.DoesNotContain( "open_tracking", json );
}


/// <summary />
[Fact]
public void Domain_deserializes_tracking_and_capabilities()
{
const string json = """
{
"id": "d91cd9bd-1176-453e-8fc1-35364d380206",
"name": "example.com",
"status": "not_started",
"created_at": "2023-04-26T20:21:26.347412+00:00",
"region": "us-east-1",
"open_tracking": true,
"click_tracking": false,
"tracking_subdomain": "links",
"capabilities": {
"sending": "enabled",
"receiving": "disabled"
},
"records": []
}
""";

var domain = JsonSerializer.Deserialize<Domain>( json );
Assert.NotNull( domain );
Assert.Equal( "links", domain!.TrackingSubdomain );
Assert.True( domain.OpenTracking );
Assert.False( domain.ClickTracking );
Assert.NotNull( domain.Capabilities );
Assert.Equal( "enabled", domain.Capabilities!.Sending );
Assert.Equal( "disabled", domain.Capabilities.Receiving );
}


/// <summary />
[Fact]
public void DomainUpdateData_serializes_tracking_subdomain()
{
var data = new DomainUpdateData()
{
TrackClicks = true,
TrackOpen = false,
TrackingSubdomain = "links",
};

var json = JsonSerializer.Serialize( data );
Assert.Contains( "\"tracking_subdomain\":\"links\"", json );
}


/// <summary />
[Fact]
public async Task JsonContent_Create_omits_null_tracking_subdomain_on_update()
{
var data = new DomainUpdateData()
{
TrackClicks = true,
TrackOpen = true,
TrackingSubdomain = null,
};

using var content = JsonContent.Create( data );
var json = await content.ReadAsStringAsync();
Assert.DoesNotContain( "tracking_subdomain", json );
}
}
Loading