Skip to content

Usr/matt.soler/threading issue #55

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 31, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,7 @@ public SendResponse RunExample()
var metadata = new List<IMetadata>()
{
new Metadata("example-type", "basic-send-complex"),
new Metadata()
{
Key = "message-contains",
Value = "attachments, headers"
}
new Metadata("message-contains","attachments, headers")
};
message.Metadata.Add(metadata);
message.Metadata.Add("x-mycustommetadata", "I am custom metadata");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,7 @@ public SendResponse RunExample()
var metadata = new List<IMetadata>()
{
new Metadata("example-type", "bulk-send-complex"),
new Metadata()
{
Key = "message-contains",
Value = "attachments, headers"
}
new Metadata("message-contains","attachments, headers")
};
message.Metadata.Add(metadata);
message.Metadata.Add("x-mycustommetadata", "I am custom metadata");
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ The SocketLabs Email Delivery C# library allows you to easily send email message
# Prerequisites and Installation
## Prerequisites
* A supported .NET version
* .NET version 4.5 or higher
* .NET Core 1.0 or higher
* .NET Standard 1.3 or higher
* .NET Framework version 4.8 or higher
* .NET 8.0 or higher
* .NET Standard 2.0 or higher
* A SocketLabs account. If you don't have one yet, you can [sign up for a free account](https://signup.socketlabs.com/step-1?plan=free) to get started.

## Installation
Expand All @@ -36,7 +36,7 @@ PM> Install-Package SocketLabs.EmailDelivery
Adding a Package Reference to your project:

```
<PackageReference Include="SocketLabs.EmailDelivery" Version="1.4.3" />
<PackageReference Include="SocketLabs.EmailDelivery" Version="2.0.0" />
```

.NET CLI users can also use the following command:
Expand Down
10 changes: 10 additions & 0 deletions docs/release-notes/2.0.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## 2.0.0

* Fix issue with ApiKey being unset for bearer type keys
* Add explicit support for .NET 8.0 and .NET 9.0
* Update dependencies
* Implement nullable pattern

```note
This is a breaking change. Some objects require constructor initialization now.
```
4 changes: 2 additions & 2 deletions src/SocketLabs/InjectionApi/AddressResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class AddressResult
/// <summary>
/// The recipient's email address.
/// </summary>
public string EmailAddress { get; set; }
public string? EmailAddress { get; set; }

/// <summary>
/// Whether the recipient was accepted for delivery.
Expand All @@ -18,7 +18,7 @@ public class AddressResult
/// <summary>
/// An error code detailing why the recipient was not accepted.
/// </summary>
public string ErrorCode { get; set; }
public string? ErrorCode { get; set; }

/// <summary>
/// Represents the <c>AddressResult</c> as a string. Useful for debugging.
Expand Down
2 changes: 1 addition & 1 deletion src/SocketLabs/InjectionApi/Core/ApiKeyParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace SocketLabs.InjectionApi.Core
/// <summary>
/// Parses a provided api key and provides a result
/// </summary>
public class ApiKeyParser : IApiKeyParser
internal class ApiKeyParser : IApiKeyParser
{
/// <summary>
/// Parses the provided Api key.
Expand Down
2 changes: 1 addition & 1 deletion src/SocketLabs/InjectionApi/Core/IApiKeyParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace SocketLabs.InjectionApi.Core
{
public interface IApiKeyParser
internal interface IApiKeyParser
{
ApiKeyParseResult Parse(string wholeApiKey);
}
Expand Down
75 changes: 40 additions & 35 deletions src/SocketLabs/InjectionApi/Core/InjectionRequestFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ namespace SocketLabs.InjectionApi.Core
internal class InjectionRequestFactory : IInjectionRequestFactory
{
private readonly int _serverId;
private readonly string _apiKey;
private readonly string? _apiKey;

/// <summary>
/// Creates a new instance of the <c>InjectionRequestFactory</c>.
/// </summary>
/// <param name="serverId">Your SocketLabs ServerId number.</param>
/// <param name="apiKey">Your SocketLabs Injection API key.</param>
public InjectionRequestFactory(int serverId, string apiKey)
/// <param name="apiKey">Your SocketLabs Injection API key. Set to null if using Bearer token.</param>
public InjectionRequestFactory(int serverId, string? apiKey)
{
_serverId = serverId;
_apiKey = apiKey;
Expand All @@ -41,7 +41,7 @@ public InjectionRequest GenerateRequest(IBasicMessage message)

request.Messages.Add(jsonMsg);

if (message.ReplyTo != null)
if (message.ReplyTo?.Email is not null)
jsonMsg.ReplyTo = new AddressJson(message.ReplyTo.Email, message.ReplyTo.FriendlyName);

return request;
Expand All @@ -63,10 +63,13 @@ public InjectionRequest GenerateRequest(IBulkMessage message)

// handle merge data per recipient for message
var mergeDataForEmail = GetBulkMergeFields(message.To);
jsonMsg.MergeData.PerMessage = mergeDataForEmail;
jsonMsg.MergeData = new()
{
PerMessage = mergeDataForEmail,

// handle global (per message) merge data
jsonMsg.MergeData.Global = PopulateMergeData(message.GlobalMergeData);
// handle global (per message) merge data
Global = PopulateMergeData(message.GlobalMergeData)
};

request.Messages.Add(jsonMsg);

Expand All @@ -90,18 +93,19 @@ internal virtual MessageJson GenerateBaseMessageJson(IMessageBase message)
MailingId = message.MailingId,
MessageId = message.MessageId,
CharSet = message.CharSet,
CustomHeaders = PopulateCustomHeaders(message.CustomHeaders),
From = new AddressJson(message.From.Email, message.From.FriendlyName),
CustomHeaders = PopulateCustomHeaders(message.CustomHeaders),
Attachments = PopulateList(message.Attachments),
Metadata = PopulateMetadata(message.Metadata),
Tags = PopulateTags(message.Tags)
};
if (message.From?.Email is not null)
jsonMsg.From = new AddressJson(message.From.Email, message.From.FriendlyName);

if (message.ReplyTo != null)
if (message.ReplyTo?.Email is not null)
jsonMsg.ReplyTo = new AddressJson(message.ReplyTo.Email, message.ReplyTo.FriendlyName);

if (message.ApiTemplate.HasValue)
jsonMsg.ApiTemplate = message.ApiTemplate.ToString();
jsonMsg.ApiTemplate = message.ApiTemplate?.ToString();

return jsonMsg;
}
Expand All @@ -113,9 +117,6 @@ internal virtual MessageJson GenerateBaseMessageJson(IMessageBase message)
/// <returns>A <c><![CDATA[ List<AttachmentJson> ]]></c> used in generating an InjectionRequest</returns>
internal virtual List<AttachmentJson> PopulateList(IEnumerable<IAttachment> attachments)
{
if (attachments == null)
return null;

var results = new List<AttachmentJson>();

foreach (var attachment in attachments)
Expand All @@ -140,8 +141,8 @@ internal virtual List<AttachmentJson> PopulateList(IEnumerable<IAttachment> atta
/// <returns>A <c><![CDATA[ List<CustomHeadersJson> ]]></c> used in generating an InjectionRequest</returns>
internal virtual List<CustomHeadersJson> PopulateCustomHeaders(IList<ICustomHeader> customHeaders)
{
var result = customHeaders?.Select(item => new CustomHeadersJson(item.Name, item.Value));
return result?.ToList();
var result = customHeaders.Select(item => new CustomHeadersJson(item.Name, item.Value));
return result.ToList();
}

/// <summary>
Expand All @@ -151,33 +152,37 @@ internal virtual List<CustomHeadersJson> PopulateCustomHeaders(IList<ICustomHead
/// <returns>A <c><![CDATA[ List<AddressJson> ]]></c> used in generating an InjectionRequest</returns>
internal virtual List<AddressJson> PopulateList(IEnumerable<IEmailAddress> recipients)
{
var result = recipients?.Select(item => new AddressJson(item.Email, item.FriendlyName));
return result?.ToList();
var result = recipients.Where(x => x.Email is not null)
.Select(item => new AddressJson(item.Email!, item.FriendlyName));

return result.ToList();
}

/// <summary>
/// Converting a <c><![CDATA[ IEnumerable<IBulkRecipient> ]]></c> to a <c><![CDATA[ List<List<MergeFieldJson>> ]]></c>
/// </summary>
/// <param name="recipients">A <c><![CDATA[ IEnumerable<IBulkRecipient> ]]></c> from the message</param>
/// <returns>A <c><![CDATA[ List<List<MergeFieldJson>> ]]></c> used in generating an InjectionRequest</returns>
internal virtual List<List<MergeFieldJson>> GetBulkMergeFields(IEnumerable<IBulkRecipient> recipients)
internal virtual List<List<MergeFieldJson>> GetBulkMergeFields(IEnumerable<IBulkRecipient>? recipients)
{
var result = new List<List<MergeFieldJson>>();

//each recipient get's their own list of merge fields
foreach (var recipient in recipients)
if (recipients is not null)
{
// Get any merge data associated with the Recipients and put it in the MergeData section
var recipientMergeFields = recipient.MergeData?.Select(mergeField => new MergeFieldJson(mergeField.Key, mergeField.Value)).ToList() ??
new List<MergeFieldJson>();
//each recipient get's their own list of merge fields
foreach (var recipient in recipients)
{
// Get any merge data associated with the Recipients and put it in the MergeData section
var recipientMergeFields = recipient.MergeData?.Select(mergeField => new MergeFieldJson(mergeField.Key, mergeField.Value)).ToList() ??
new List<MergeFieldJson>();

recipientMergeFields.Add(new MergeFieldJson("DeliveryAddress", recipient.Email));
recipientMergeFields.Add(new MergeFieldJson("DeliveryAddress", recipient.Email));

//don't include friendly name if it hasn't been provided
if (!string.IsNullOrWhiteSpace(recipient.FriendlyName))
recipientMergeFields.Add(new MergeFieldJson("RecipientName", recipient.FriendlyName));
//don't include friendly name if it hasn't been provided
if (!string.IsNullOrWhiteSpace(recipient.FriendlyName))
recipientMergeFields.Add(new MergeFieldJson("RecipientName", recipient.FriendlyName!));

result.Add(recipientMergeFields);
result.Add(recipientMergeFields);
}
}

return result;
Expand All @@ -191,8 +196,8 @@ internal virtual List<List<MergeFieldJson>> GetBulkMergeFields(IEnumerable<IBulk
internal virtual List<MergeFieldJson> PopulateMergeData(IDictionary<string, string> mergeData)
{

var result = mergeData?.Select(item => new MergeFieldJson(item.Key, item.Value));
return result?.ToList();
var result = mergeData.Select(item => new MergeFieldJson(item.Key, item.Value));
return result.ToList();
}


Expand All @@ -203,8 +208,8 @@ internal virtual List<MergeFieldJson> PopulateMergeData(IDictionary<string, stri
/// <returns>A <c><![CDATA[ List<MetadataHeaderJson> ]]></c> used in generating an InjectionRequest</returns>
internal virtual List<MetadataHeaderJson> PopulateMetadata(IList<IMetadata> metadata)
{
var result = metadata?.Select(item => new MetadataHeaderJson(item.Key, item.Value));
return result?.ToList();
var result = metadata.Select(item => new MetadataHeaderJson(item.Key, item.Value));
return result.ToList();
}

/// <summary>
Expand All @@ -215,7 +220,7 @@ internal virtual List<MetadataHeaderJson> PopulateMetadata(IList<IMetadata> meta
internal virtual List<string> PopulateTags(IList<string> tags)
{
var result = tags.ToList();
return result?.ToList();
return result;
}
}
}
8 changes: 8 additions & 0 deletions src/SocketLabs/InjectionApi/Core/InjectionResponseParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ public SendResponse Parse(HttpResponseMessage httpResponse)

var injectionResponse = JsonConvert.DeserializeObject<InjectionResponseDto>(contentString);

if (injectionResponse is null)
{
return new SendResponse()
{
Result = SendResult.UnknownError
};
}

var resultEnum = DetermineSendResult(injectionResponse, httpResponse);
var newResponse = new SendResponse
{
Expand Down
4 changes: 2 additions & 2 deletions src/SocketLabs/InjectionApi/Core/SendValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ internal virtual List<AddressResult> HasInvalidRecipients(IBulkMessage message)
/// <returns>A <c><![CDATA[ List<AddressResult> ]]></c> if an invalid email address is found.</returns>
/// <see cref="IEmailAddress"/>
/// <see cref="AddressResult"/>
internal virtual List<AddressResult> FindInvalidRecipients(IList<IEmailAddress> recipients)
internal virtual List<AddressResult>? FindInvalidRecipients(IList<IEmailAddress>? recipients)
{
var invalid = recipients?.Where(item => !item.IsValid).Select(x => new AddressResult()
{
Expand All @@ -312,7 +312,7 @@ internal virtual List<AddressResult> FindInvalidRecipients(IList<IEmailAddress>
/// <returns>A <c><![CDATA[ List<AddressResult> ]]></c> if an invalid email address is found.</returns>
/// <see cref="IBulkRecipient"/>
/// <see cref="AddressResult"/>
internal virtual List<AddressResult> FindInvalidRecipients(IList<IBulkRecipient> recipients)
internal virtual List<AddressResult>? FindInvalidRecipients(IList<IBulkRecipient> recipients)
{
var invalid = recipients?.Where(item => !item.IsValid).Select(x => new AddressResult()
{
Expand Down
4 changes: 2 additions & 2 deletions src/SocketLabs/InjectionApi/Core/Serialization/AddressJson.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ internal class AddressJson
/// </summary>
/// <param name="emailAddress">A valid email address</param>
/// <param name="friendlyName">The friendly or display name for the recipient.</param>
public AddressJson(string emailAddress, string friendlyName = null)
public AddressJson(string emailAddress, string? friendlyName = null)
{
EmailAddress = emailAddress;
FriendlyName = friendlyName;
Expand All @@ -25,6 +25,6 @@ public AddressJson(string emailAddress, string friendlyName = null)
/// <summary>
/// The friendly or display name for the recipient.
/// </summary>
public string FriendlyName { get; set; }
public string? FriendlyName { get; set; }
}
}
10 changes: 5 additions & 5 deletions src/SocketLabs/InjectionApi/Core/Serialization/AttachmentJson.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,27 @@ internal class AttachmentJson
/// <summary>
/// Name of attachment (displayed in email clients)
/// </summary>
public string Name { get; set; }
public string? Name { get; set; }

/// <summary>
/// The BASE64 encoded string containing the contents of an attachment.
/// </summary>
public string Content { get; set; }
public string? Content { get; set; }

/// <summary>
/// When set, used to embed an image within the body of an email message.
/// </summary>
public string ContentId { get; set; }
public string? ContentId { get; set; }

/// <summary>
/// The ContentType (MIME type) of the attachment.
/// </summary>
/// <example>text/plain, image/jpeg, </example>
public string ContentType { get; set; }
public string? ContentType { get; set; }

/// <summary>
/// A list of custom headers added to the attachment.
/// </summary>
public List<CustomHeadersJson> CustomHeaders { get; set; }
public List<CustomHeadersJson> CustomHeaders { get; set; } = new();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,29 @@ internal class InjectionRequest
/// <summary>
/// Your SocketLabs ServerId number.
/// </summary>
public int ServerId { get; internal set; }
public readonly int _serverId;

/// <summary>
/// Your SocketLabs Injection API key.
/// </summary>
public string ApiKey { get; internal set; }
public readonly string? _apiKey;

/// <summary>
/// Creates a new instance of the <c>InjectionRequest</c> class.
/// </summary>
/// <param name="serverId">Your SocketLabs ServerId number.</param>
/// <param name="apiKey">Your SocketLabs Injection API key.</param>
public InjectionRequest(int serverId, string apiKey)
public InjectionRequest(int serverId, string? apiKey)
{
ServerId = serverId;
ApiKey = apiKey;
_serverId = serverId;
_apiKey = apiKey;
Messages = new List<MessageJson>();
}

/// <summary>
/// Gets or sets the list of messages to be sent.
/// </summary>
public List<MessageJson> Messages { get; set; }
public List<MessageJson> Messages { get; set; } = new();

/// <summary>
/// Get the InjectionRequest object serialized into a JSON string
Expand Down
Loading