diff --git a/Wave/Controllers/WebhookController.cs b/Wave/Controllers/WebhookController.cs index 0463633..01d4d37 100644 --- a/Wave/Controllers/WebhookController.cs +++ b/Wave/Controllers/WebhookController.cs @@ -15,16 +15,15 @@ public class WebhookController(ILogger logger, ApplicationDbC [HttpPost("mailtrap/{apiKey}")] [Authorize("EmailApi", AuthenticationSchemes = "ApiKeyInRoute")] public async Task Mailtrap(Webhook webhook, string apiKey) { + logger.LogDebug("Start processing webhook events"); foreach (var webhookEvent in webhook.Events) { metrics.WebhookEventReceived("Mailtrap", webhookEvent.Type.ToString()); var subscriber = await context.Set().FirstOrDefaultAsync(s => s.Email == webhookEvent.Email); - logger.LogDebug("Received Webhook event {EventType} for {email}", - webhookEvent.Type, webhookEvent.Email); - + logger.LogDebug("Received {WebhookEvent} event for {email}", webhookEvent.Type, webhookEvent.Email); if (subscriber is null) { logger.LogWarning( - "Received webhook event from mailtrap of type {EventType}, " + + "Received {WebhookEvent} from Mailtrap " + "but failed to find subscriber with E-Mail {email}.", webhookEvent.Type, webhookEvent.Email); metrics.WebhookEventError("Mailtrap", webhookEvent.Type.ToString(), "unknown email"); @@ -39,14 +38,13 @@ public class WebhookController(ILogger logger, ApplicationDbC case WebhookEventType.Open: subscriber.LastMailOpened = webhookEvent.EventDateTime; break; - case WebhookEventType.Bounce: - // Store this message in case it develops into a suspension - subscriber.UnsubscribeReason = webhookEvent.Response; + case WebhookEventType.SoftBounce: + subscriber.UnsubscribeReason = webhookEvent.Response ?? webhookEvent.Type.Humanize(LetterCasing.Title); break; case WebhookEventType.Suspension: - logger.LogWarning("Received Suspension event, you may have send from an unverifyied domain or exceeded your hourly rate."); - return Ok(); - break; + logger.LogWarning( + "Received Suspension event, you may have send from an unverified domain or exceeded your hourly rate."); + continue; case WebhookEventType.Unsubscribe: subscriber.Unsubscribed = true; subscriber.UnsubscribeReason = "User Unsubscribed"; @@ -55,22 +53,23 @@ public class WebhookController(ILogger logger, ApplicationDbC subscriber.Unsubscribed = true; subscriber.UnsubscribeReason = "User reported as Spam"; break; + case WebhookEventType.Bounce: case WebhookEventType.Reject: subscriber.Unsubscribed = true; - subscriber.UnsubscribeReason = webhookEvent.Reason?.Humanize().Titleize() ?? "Rejected"; + subscriber.UnsubscribeReason = webhookEvent.Reason ?? webhookEvent.Type.Humanize(LetterCasing.Title); break; - case WebhookEventType.SoftBounce: case WebhookEventType.Click: default: logger.LogInformation("Received unsupported event {EventType} for {email}. Skipping.", webhookEvent.Type, webhookEvent.Email); metrics.WebhookEventError("Mailtrap", webhookEvent.Type.ToString(), "unknown type"); - return Ok(); + continue; } - await context.SaveChangesAsync(); logger.LogDebug("Webhook event {EventType} for {email} processed successfully.", webhookEvent.Type, webhookEvent.Email); } + await context.SaveChangesAsync(); + logger.LogDebug("All webhook events processed and saved"); return Ok(); diff --git a/Wave/Data/Api/Mailtrap/WebhookEvent.cs b/Wave/Data/Api/Mailtrap/WebhookEvent.cs index 9f675eb..6cbc76d 100644 --- a/Wave/Data/Api/Mailtrap/WebhookEvent.cs +++ b/Wave/Data/Api/Mailtrap/WebhookEvent.cs @@ -1,14 +1,18 @@ -using System.Text.Json.Serialization; +using System.Runtime.Serialization; +using System.Text.Json.Serialization; namespace Wave.Data.Api.Mailtrap; +[JsonConverter(typeof(JsonStringEnumConverter))] public enum WebhookEventType { Delivery, + [EnumMember(Value = "soft bounce")] SoftBounce, Bounce, Suspension, Unsubscribe, Open, + [EnumMember(Value = "spam complaint")] SpamComplaint, Click, Reject @@ -34,7 +38,7 @@ public record WebhookEvent( [property:JsonPropertyName("response_code")] int? ResponseCode) { - public WebhookEventType Type => Enum.Parse(EventTypeString.Replace("_", ""), true); + public WebhookEventType Type => Enum.Parse(EventTypeString.Replace("_", "").Replace(" ", ""), true); public DateTimeOffset EventDateTime => DateTimeOffset.FromUnixTimeSeconds(Timestamp); }