diff --git a/src/SparkPost.Tests/DataMapperTests.cs b/src/SparkPost.Tests/DataMapperTests.cs index b10e856c..43eaeb89 100644 --- a/src/SparkPost.Tests/DataMapperTests.cs +++ b/src/SparkPost.Tests/DataMapperTests.cs @@ -209,6 +209,85 @@ public void It_should_set_the_recipients() ["email"].ShouldEqual(recipient2.Address.Email); } + [TestCaseSource("SinkifyCases")] + public void It_should_sinkify_addresses(string email, string headerTo, + string expectedEmail, string expectedHeaderTo) + { + var address = new Address() { Email = email, HeaderTo = headerTo }; + transmission.Recipients.Add(new Recipient() { Address = address }); + transmission.Options.Sink = true; + + var result = mapper.ToDictionary(transmission)["recipients"] as IEnumerable>; + + result.Count().ShouldEqual(1); + var resultAddress = result.Single()["address"].CastAs>(); + + foreach (var fieldToTest in new Dictionary() { + { "email", expectedEmail }, { "header_to", expectedHeaderTo} }) + { + if (fieldToTest.Value == null) + resultAddress.ContainsKey(fieldToTest.Key).ShouldBeFalse(); + else + resultAddress[fieldToTest.Key].ShouldEqual(fieldToTest.Value); + } + } + + static object[] SinkifyCases = + { + new string[] + { + "bob@example.com", + "larry@example.com", + "bob@example.com.sink.sparkpostmail.com", + "larry@example.com.sink.sparkpostmail.com" + }, + new string[] + { + "bob@example.com", + null, + "bob@example.com.sink.sparkpostmail.com", + null + }, + new string[] + { + "bob@example.com.sink.sparkpostmail.com", + "larry@example.com", + "bob@example.com.sink.sparkpostmail.com", + "larry@example.com.sink.sparkpostmail.com" + }, + new string[] + { + "bob@example.com.SINK.SPARKPOSTMAIL.COM", + "larry@example.com", + "bob@example.com.SINK.SPARKPOSTMAIL.COM", + "larry@example.com.sink.sparkpostmail.com" + }, + new string[] + { + null, null, null, null + }, + }; + + [TestCase(true, true, true)] + [TestCase(true, false, true)] + [TestCase(false, true, true)] + [TestCase(false, false, false)] + public void Client_sink_setting_should_override_transmission(bool clientUseSink, + bool transmissionUseSink, bool shouldSinkify) + { + var address = new Address() { Email = Guid.NewGuid().ToString() }; + transmission.Recipients.Add(new Recipient() { Address = address }); + transmission.Options.Sink = transmissionUseSink; + + var result = mapper.ToDictionary(transmission, clientUseSink)["recipients"] as IEnumerable>; + var resultAddress = result.Single()["address"].CastAs>(); + + resultAddress["email"] + .CastAs() + .EndsWith(".sink.sparkpostmail.com") + .ShouldEqual(shouldSinkify); + } + [Test] public void It_should_set_the_recipients_to_a_list_id_if_a_list_id_is_provided() { diff --git a/src/SparkPost/Client.cs b/src/SparkPost/Client.cs index 556f4ef6..4083a9f6 100644 --- a/src/SparkPost/Client.cs +++ b/src/SparkPost/Client.cs @@ -82,6 +82,7 @@ public Settings() } public SendingModes SendingMode { get; set; } + public bool SinkAllTransmissions { get; set; } public HttpClient CreateANewHttpClient() { diff --git a/src/SparkPost/DataMapper.cs b/src/SparkPost/DataMapper.cs index ac3ce89b..77f0933e 100644 --- a/src/SparkPost/DataMapper.cs +++ b/src/SparkPost/DataMapper.cs @@ -16,6 +16,7 @@ public interface IDataMapper IDictionary ToDictionary(SendingDomainStatus sendingDomainStatus); IDictionary ToDictionary(VerifySendingDomain verifySendingDomain); IDictionary ToDictionary(Transmission transmission); + IDictionary ToDictionary(Transmission transmission, bool useSink); IDictionary ToDictionary(Recipient recipient); IDictionary ToDictionary(Address address); IDictionary ToDictionary(Options options); @@ -81,6 +82,11 @@ public virtual IDictionary ToDictionary(VerifySendingDomain veri } public virtual IDictionary ToDictionary(Transmission transmission) + { + return ToDictionary(transmission, false); + } + + public virtual IDictionary ToDictionary(Transmission transmission, bool sink) { var data = new Dictionary { @@ -95,6 +101,8 @@ public virtual IDictionary ToDictionary(Transmission transmissio var result = WithCommonConventions(transmission, data); + if (sink || transmission.Options.Sink) + SinkHandling.AddSinkDomainToAddresses(result); CcHandling.Process(transmission, result); return result; @@ -129,7 +137,12 @@ public virtual IDictionary ToDictionary(Address address) public virtual IDictionary ToDictionary(Options options) { - return AnyValuesWereSetOn(options) ? WithCommonConventions(options) : null; + var result = WithCommonConventions(options, new Dictionary() + { + ["sink"] = null, + }); + + return result.Any() ? result : null; } public virtual IDictionary ToDictionary(Content content) diff --git a/src/SparkPost/Options.cs b/src/SparkPost/Options.cs index 3c90d2c6..6a1905ba 100644 --- a/src/SparkPost/Options.cs +++ b/src/SparkPost/Options.cs @@ -12,5 +12,6 @@ public class Options public bool? SkipSuppression { get; set; } public bool? InlineCss { get; set; } public string IpPool { get; set; } + public bool Sink { get; set; } } } \ No newline at end of file diff --git a/src/SparkPost/SinkHandling.cs b/src/SparkPost/SinkHandling.cs new file mode 100644 index 00000000..e908328a --- /dev/null +++ b/src/SparkPost/SinkHandling.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace SparkPost +{ + internal static class SinkHandling + { + private static readonly string SINK_DOMAIN = ".sink.sparkpostmail.com"; + + internal static void AddSinkDomainToAddresses(IDictionary result) + { + if (result.ContainsKey("recipients")) + { + var recipients = (result["recipients"] as IEnumerable>).ToList(); + foreach (var address in recipients + .Where(r => r.ContainsKey("address")) + .Select(r => r["address"]) + .Cast>()) + { + AddSinkDomainToAddress(address, "email"); + AddSinkDomainToAddress(address, "header_to"); + } + result["recipients"] = recipients; + } + } + + private static void AddSinkDomainToAddress(IDictionary address, string fieldName) + { + if (address.ContainsKey(fieldName)) + { + var currentAddress = (string)address[fieldName]; + if (!String.IsNullOrWhiteSpace(currentAddress) && !currentAddress.EndsWith(SINK_DOMAIN, true, null)) + address[fieldName] = currentAddress + SINK_DOMAIN; + + } + } + } +} diff --git a/src/SparkPost/SparkPost.csproj b/src/SparkPost/SparkPost.csproj index 0354bcc6..d82190b4 100644 --- a/src/SparkPost/SparkPost.csproj +++ b/src/SparkPost/SparkPost.csproj @@ -93,6 +93,7 @@ + diff --git a/src/SparkPost/Transmissions.cs b/src/SparkPost/Transmissions.cs index 42c09478..8bcecc6c 100644 --- a/src/SparkPost/Transmissions.cs +++ b/src/SparkPost/Transmissions.cs @@ -21,12 +21,12 @@ public Transmissions(Client client, IRequestSender requestSender, DataMapper dat } public async Task Send(Transmission transmission) - { + { var request = new Request { Url = $"api/{client.Version}/transmissions", Method = "POST", - Data = dataMapper.ToDictionary(transmission) + Data = dataMapper.ToDictionary(transmission, client.CustomSettings.SinkAllTransmissions) }; var response = await requestSender.Send(request);