Overview
NuGet.Services.Messaging is a small, focused library that forms the bridge between the NuGet Gallery frontend (the email sender) and the back-end email processing job (the email consumer). It defines the canonical EmailMessageData model that both sides agree on, the IEmailMessageEnqueuer interface that the frontend uses to dispatch email without knowing the delivery mechanism, and the ServiceBusMessageSerializer that translates between EmailMessageData and Azure Service Bus brokered messages.
The library encodes one deliberate GDPR constraint directly in the serializer: every Service Bus message is given a time-to-live of exactly two days. Because email message payloads can contain personally identifiable information (recipient addresses, user names, etc.), this hard-coded TTL ensures that un-processed messages are automatically purged by the broker before they can linger indefinitely.
The project targets both net472 and netstandard2.0, which allows it to be referenced by the full-framework NuGetGallery web application and by any future .NET Standard-compatible services without modification. It has no direct Azure SDK dependency of its own; all Azure Service Bus types are abstracted behind interfaces defined in NuGet.Services.Contracts and implemented in NuGet.Services.ServiceBus.
Role in System
NuGet.Services.Messaging sits in the middle of the asynchronous email pipeline. The gallery frontend constructs an EmailMessageData value, hands it to IEmailMessageEnqueuer, which serializes it and publishes it to an Azure Service Bus topic. A separate back-end job subscribes to that topic, deserializes the message using the same IServiceBusMessageSerializer, and performs the actual SMTP delivery.
Shared Data Contract
EmailMessageData is the single agreed-upon model for an email message. It carries subject, plain-text body, HTML body, sender, To/CC/Bcc/ReplyTo recipient lists, a tracking GUID, and a delivery count populated on the consumer side.Enqueuing Abstraction
IEmailMessageEnqueuer hides the Service Bus publishing details from callers. The concrete EmailMessageEnqueuer serializes the message, calls ITopicClient.SendAsync, and emits structured log entries at Trace and Information level for each step.Versioned Schema Serialization
ServiceBusMessageSerializer uses the generic BrokeredMessageSerializer<T> from NuGet.Services.ServiceBus together with a private [Schema(Name = "EmailMessageData", Version = 1)] inner class. Schema name and version are stored as Service Bus message properties and validated on deserialization.GDPR-Enforced TTL
Messages are given a two-day TTL at serialization time. This is a hard-coded policy (not configuration) that ensures PII-containing email payloads are automatically expired by the broker if they are not consumed promptly.
Key Files and Classes
Dependencies
NuGet Package References
Internal Project References
Notable Patterns and Implementation Details
The
EmailMessageData1 inner class in ServiceBusMessageSerializer is private and versioned with [Schema(Name = "EmailMessageData", Version = 1)]. This versioning scheme means that a schema change (adding, removing, or modifying a property) requires incrementing the version number and adding a new inner class (e.g., EmailMessageData2). The deserializer enforces the version at runtime and throws FormatException if the message was produced by a different schema version.EmailMessageEnqueuer logs the MessageTrackingId GUID at every step using structured logging. This allows operators to correlate a specific email message across the frontend log (where it was enqueued) and the backend log (where it was processed or failed) by searching for the same tracking ID value.