summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md10
-rw-r--r--README.md21
-rw-r--r--SendGrid/Example/Program.cs1
-rw-r--r--SendGrid/SendGrid/Properties/AssemblyInfo.cs8
-rw-r--r--SendGrid/SendGridMail/Properties/AssemblyInfo.cs4
-rw-r--r--SendGrid/SendGridMail/Transport/Web.cs299
-rw-r--r--SendGrid/Tests/Transport/TestWebApi.cs141
7 files changed, 253 insertions, 231 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 44c06cf..34aa6fa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,14 +1,18 @@
-# Change Log
+# Change Log
All notable changes to this project will be documented in this file.
+## [6.3.0] - 2015-11-24
+###Added
+- Send emails using API Key
+
## [6.2.0] - 2015-11-18
###Added
-- Added support for using the Web API v3 endpoints.
+- Added support for using the Web API v3 endpoints
- Implemented the api_keys endpoint [GET, POST, PATCH, DELETE]
## [6.1.0] - 2015-4-27
###Added
-- Added support for sending via API keys in addition to credentials. Pass an API Key string to the Web transport constructor.
+- Added support for sending via API keys in addition to credentials. Pass an API Key string to the Web transport constructor
## [6.0.1] - 2015-4-24
###Fixed
diff --git a/README.md b/README.md
index bbfd8bf..dd28d28 100644
--- a/README.md
+++ b/README.md
@@ -61,17 +61,8 @@ After creating an email message, you can send it using the Web API provided by S
Sending email requires that you supply your SendGrid account credentials (username and password) OR a SendGrid API Key. API Key is the preferred method. API Keys are in beta. To configure API keys, visit https://sendgrid.com/beta/settings/api_keys
-Using Credentials
-```csharp
-// Create network credentials to access your SendGrid account.
-var username = "your_sendgrid_username";
-var pswd = "your_sendgrid_password";
-
-var credentials = new NetworkCredential(username, pswd);
-```
To send an email message, use the **DeliverAsync** method on the **Web** transport class, which calls the SendGrid Web API. The following example shows how to send a message.
-
```csharp
// Create the email object first, then add the properties.
SendGridMessage myMessage = new SendGridMessage();
@@ -80,18 +71,12 @@ myMessage.From = new MailAddress("john@example.com", "John Smith");
myMessage.Subject = "Testing the SendGrid Library";
myMessage.Text = "Hello World!";
-// Create credentials, specifying your user name and password.
-var credentials = new NetworkCredential("username", "password");
-
-// Create an Web transport for sending email, using credentials...
-//var transportWeb = new Web(credentials);
-
-// ...OR create a Web transport, using API Key (preferred)
-var transportWeb = new Web("This string is an API key");
+// Create a Web transport, using API Key
+var transportWeb = new Web("This string is a SendGrid API key");
// Send the email.
transportWeb.DeliverAsync(myMessage);
-// If your developing a Console Application, use the following
+// NOTE: If your developing a Console Application, use the following so that the API call has time to complete
// transportWeb.DeliverAsync(myMessage).Wait();
```
diff --git a/SendGrid/Example/Program.cs b/SendGrid/Example/Program.cs
index 1d4fbf3..e3a807a 100644
--- a/SendGrid/Example/Program.cs
+++ b/SendGrid/Example/Program.cs
@@ -24,7 +24,6 @@ namespace Example
private static void SendAsync(SendGrid.SendGridMessage message)
{
string apikey = Environment.GetEnvironmentVariable("SENDGRID_APIKEY");
-
// Create a Web transport for sending email.
var transportWeb = new SendGrid.Web(apikey);
diff --git a/SendGrid/SendGrid/Properties/AssemblyInfo.cs b/SendGrid/SendGrid/Properties/AssemblyInfo.cs
index ce788f2..84b1ab9 100644
--- a/SendGrid/SendGrid/Properties/AssemblyInfo.cs
+++ b/SendGrid/SendGrid/Properties/AssemblyInfo.cs
@@ -6,9 +6,9 @@ using System.Runtime.InteropServices;
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SendGrid")]
-[assembly: AssemblyDescription("")]
+[assembly: AssemblyDescription("A client library for SendGrid Web API v3 endpoints")]
[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
+[assembly: AssemblyCompany("SendGrid")]
[assembly: AssemblyProduct("SendGrid")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion("6.3.0")]
+[assembly: AssemblyFileVersion("6.3.0")]
diff --git a/SendGrid/SendGridMail/Properties/AssemblyInfo.cs b/SendGrid/SendGridMail/Properties/AssemblyInfo.cs
index 5ca685d..bedd624 100644
--- a/SendGrid/SendGridMail/Properties/AssemblyInfo.cs
+++ b/SendGrid/SendGridMail/Properties/AssemblyInfo.cs
@@ -58,5 +58,5 @@ using System.Runtime.InteropServices;
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("6.0.0")]
-[assembly: AssemblyFileVersion("6.0.0")] \ No newline at end of file
+[assembly: AssemblyVersion("6.3.0")]
+[assembly: AssemblyFileVersion("6.3.0")] \ No newline at end of file
diff --git a/SendGrid/SendGridMail/Transport/Web.cs b/SendGrid/SendGridMail/Transport/Web.cs
index c42ad49..dbf5d28 100644
--- a/SendGrid/SendGridMail/Transport/Web.cs
+++ b/SendGrid/SendGridMail/Transport/Web.cs
@@ -12,154 +12,175 @@ using SendGrid.SmtpApi;
// ReSharper disable MemberCanBePrivate.Global
namespace SendGrid
{
- public class Web : ITransport
- {
- #region Properties
-
- //TODO: Make this configurable
- public const String Endpoint = "https://api.sendgrid.com/api/mail.send.xml";
-
- private readonly NetworkCredential _credentials;
- private readonly HttpClient _client;
-
- #endregion
-
- /// <summary>
- /// Creates a new Web interface for sending mail
- /// </summary>
- /// <param name="credentials">SendGridMessage user parameters</param>
+ public class Web : ITransport
+ {
+ #region Properties
+
+ //TODO: Make this configurable
+ public const String Endpoint = "https://api.sendgrid.com/api/mail.send.xml";
+ private readonly NetworkCredential _credentials;
+ private readonly HttpClient _client;
+ private readonly string _apiKey;
+
+ #endregion
+
+ /// <summary>
+ /// Creates a new Web interface for sending mail
+ /// </summary>
+ /// <param name="apiKey">The API Key with which to send</param>
+ public Web(string apiKey)
+ : this(apiKey, null, TimeSpan.FromSeconds(100)) { }
+
+ /// <summary>
+ /// Creates a new Web interface for sending mail
+ /// </summary>
+ /// <param name="credentials">SendGridMessage user parameters</param>
public Web(NetworkCredential credentials)
- : this(credentials, TimeSpan.FromSeconds(100)) { }
+ : this(null, credentials, TimeSpan.FromSeconds(100)) { }
/// <summary>
/// Creates a new Web interface for sending mail.
/// </summary>
+ /// <param name="apKey">The API Key with which to send</param>
/// <param name="credentials">SendGridMessage user parameters</param>
/// <param name="httpTimeout">HTTP request timeout</param>
- public Web(NetworkCredential credentials, TimeSpan httpTimeout)
- {
- _credentials = credentials;
+ public Web(string apiKey, NetworkCredential credentials, TimeSpan httpTimeout)
+ {
+ _credentials = credentials;
_client = new HttpClient();
-
+ _apiKey = apiKey;
+
var version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
+ if (credentials == null)
+ {
+ _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _apiKey);
+ }
_client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "sendgrid/" + version + ";csharp");
_client.Timeout = httpTimeout;
- }
-
- /// <summary>
- /// Asynchronously delivers a message over SendGrid's Web interface
- /// </summary>
- /// <param name="message"></param>
- public async Task DeliverAsync(ISendGrid message)
- {
- var content = new MultipartFormDataContent();
- AttachFormParams(message, content);
- AttachFiles(message, content);
- var response = await _client.PostAsync(Endpoint, content);
- await ErrorChecker.CheckForErrorsAsync(response);
- }
-
- #region Support Methods
-
- private void AttachFormParams(ISendGrid message, MultipartFormDataContent content)
- {
- var formParams = FetchFormParams(message);
- foreach (var keyValuePair in formParams)
- {
- content.Add(new StringContent(keyValuePair.Value), keyValuePair.Key);
- }
- }
-
- private void AttachFiles(ISendGrid message, MultipartFormDataContent content)
- {
- var files = FetchFileBodies(message);
- foreach (var file in files)
- {
- var fs = new FileStream(file.Key, FileMode.Open, FileAccess.Read);
- var fileContent = new StreamContent(fs);
-
- fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
- {
- Name = "files[" + Path.GetFileName(file.Key) + "]",
- FileName = Path.GetFileName(file.Key)
- };
-
- fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
- content.Add(fileContent);
- }
-
- var streamingFiles = FetchStreamingFileBodies(message);
- foreach (var file in streamingFiles)
- {
- var stream = file.Value;
- var fileContent = new StreamContent(stream);
-
- fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
- {
- Name = "files[" + Path.GetFileName(file.Key) + "]",
- FileName = Path.GetFileName(file.Key)
- };
-
- fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
- content.Add(fileContent);
- }
- }
-
-
-
- internal List<KeyValuePair<String, String>> FetchFormParams(ISendGrid message)
- {
- var result = new List<KeyValuePair<string, string>>
- {
- new KeyValuePair<String, String>("api_user", _credentials.UserName),
- new KeyValuePair<String, String>("api_key", _credentials.Password),
- new KeyValuePair<String, String>("headers",
- message.Headers.Count == 0 ? null : Utils.SerializeDictionary(message.Headers)),
- new KeyValuePair<String, String>("replyto",
- message.ReplyTo.Length == 0 ? null : message.ReplyTo.ToList().First().Address),
- new KeyValuePair<String, String>("from", message.From.Address),
- new KeyValuePair<String, String>("fromname", message.From.DisplayName),
- new KeyValuePair<String, String>("subject", message.Subject),
- new KeyValuePair<String, String>("text", message.Text),
- new KeyValuePair<String, String>("html", message.Html),
- new KeyValuePair<String, String>("x-smtpapi", message.Header.JsonString() ?? "")
- };
- if (message.To != null)
- {
- result = result.Concat(message.To.ToList().Select(a => new KeyValuePair<String, String>("to[]", a.Address)))
- .Concat(message.To.ToList().Select(a => new KeyValuePair<String, String>("toname[]", a.DisplayName)))
- .ToList();
- }
-
- if (message.Cc != null)
- {
- result.AddRange(message.Cc.Select(c => new KeyValuePair<string, string>("cc[]", c.Address)));
- }
-
- if (message.Bcc != null)
- {
- result.AddRange(message.Bcc.Select(c => new KeyValuePair<string, string>("bcc[]", c.Address)));
- }
-
- if (message.GetEmbeddedImages().Count > 0) {
- result = result.Concat(message.GetEmbeddedImages().ToList().Select(x => new KeyValuePair<String, String>(string.Format("content[{0}]", x.Key), x.Value)))
- .ToList();
- }
- return result.Where(r => !String.IsNullOrEmpty(r.Value)).ToList();
- }
-
- internal IEnumerable<KeyValuePair<string, MemoryStream>> FetchStreamingFileBodies(ISendGrid message)
- {
- return message.StreamedAttachments.Select(kvp => kvp).ToList();
- }
-
- internal List<KeyValuePair<String, FileInfo>> FetchFileBodies(ISendGrid message)
- {
- return message.Attachments == null
- ? new List<KeyValuePair<string, FileInfo>>()
- : message.Attachments.Select(name => new KeyValuePair<String, FileInfo>(name, new FileInfo(name))).ToList();
- }
-
- #endregion
- }
+ }
+
+ /// <summary>
+ /// Asynchronously delivers a message over SendGrid's Web interface
+ /// </summary>
+ /// <param name="message"></param>
+ public async Task DeliverAsync(ISendGrid message)
+ {
+ var content = new MultipartFormDataContent();
+ AttachFormParams(message, content);
+ AttachFiles(message, content);
+ var response = await _client.PostAsync(Endpoint, content);
+ await ErrorChecker.CheckForErrorsAsync(response);
+ }
+
+ #region Support Methods
+
+ private void AttachFormParams(ISendGrid message, MultipartFormDataContent content)
+ {
+ var formParams = FetchFormParams(message);
+ foreach (var keyValuePair in formParams)
+ {
+ content.Add(new StringContent(keyValuePair.Value), keyValuePair.Key);
+ }
+ }
+
+ private void AttachFiles(ISendGrid message, MultipartFormDataContent content)
+ {
+ var files = FetchFileBodies(message);
+ foreach (var file in files)
+ {
+ var fs = new FileStream(file.Key, FileMode.Open, FileAccess.Read);
+ var fileContent = new StreamContent(fs);
+
+ fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
+ {
+ Name = "files[" + Path.GetFileName(file.Key) + "]",
+ FileName = Path.GetFileName(file.Key)
+ };
+
+ fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
+ content.Add(fileContent);
+ }
+
+ var streamingFiles = FetchStreamingFileBodies(message);
+ foreach (var file in streamingFiles)
+ {
+ var stream = file.Value;
+ var fileContent = new StreamContent(stream);
+
+ fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
+ {
+ Name = "files[" + Path.GetFileName(file.Key) + "]",
+ FileName = Path.GetFileName(file.Key)
+ };
+
+ fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
+ content.Add(fileContent);
+ }
+ }
+
+ internal List<KeyValuePair<String, String>> FetchFormParams(ISendGrid message)
+ {
+ var result = new List<KeyValuePair<string, string>>
+ {
+ new KeyValuePair<String, String>("headers",
+ message.Headers.Count == 0 ? null : Utils.SerializeDictionary(message.Headers)),
+ new KeyValuePair<String, String>("replyto",
+ message.ReplyTo.Length == 0 ? null : message.ReplyTo.ToList().First().Address),
+ new KeyValuePair<String, String>("from", message.From.Address),
+ new KeyValuePair<String, String>("fromname", message.From.DisplayName),
+ new KeyValuePair<String, String>("subject", message.Subject),
+ new KeyValuePair<String, String>("text", message.Text),
+ new KeyValuePair<String, String>("html", message.Html),
+ new KeyValuePair<String, String>("x-smtpapi", message.Header.JsonString() ?? "")
+ };
+
+ //If the API key is not specified, use the username and password
+ if (_credentials != null)
+ {
+ var creds = new List<KeyValuePair<string, string>>
+ {
+ new KeyValuePair<string, string>("api_user", _credentials.UserName),
+ new KeyValuePair<string, string>("api_key", _credentials.Password)
+ };
+ result.AddRange(creds);
+ }
+
+ if (message.To != null)
+ {
+ result = result.Concat(message.To.ToList().Select(a => new KeyValuePair<String, String>("to[]", a.Address)))
+ .Concat(message.To.ToList().Select(a => new KeyValuePair<String, String>("toname[]", a.DisplayName)))
+ .ToList();
+ }
+
+ if (message.Cc != null)
+ {
+ result.AddRange(message.Cc.Select(c => new KeyValuePair<string, string>("cc[]", c.Address)));
+ }
+
+ if (message.Bcc != null)
+ {
+ result.AddRange(message.Bcc.Select(c => new KeyValuePair<string, string>("bcc[]", c.Address)));
+ }
+
+ if (message.GetEmbeddedImages().Count > 0) {
+ result = result.Concat(message.GetEmbeddedImages().ToList().Select(x => new KeyValuePair<String, String>(string.Format("content[{0}]", x.Key), x.Value)))
+ .ToList();
+ }
+ return result.Where(r => !String.IsNullOrEmpty(r.Value)).ToList();
+ }
+
+ internal IEnumerable<KeyValuePair<string, MemoryStream>> FetchStreamingFileBodies(ISendGrid message)
+ {
+ return message.StreamedAttachments.Select(kvp => kvp).ToList();
+ }
+
+ internal List<KeyValuePair<String, FileInfo>> FetchFileBodies(ISendGrid message)
+ {
+ return message.Attachments == null
+ ? new List<KeyValuePair<string, FileInfo>>()
+ : message.Attachments.Select(name => new KeyValuePair<String, FileInfo>(name, new FileInfo(name))).ToList();
+ }
+
+ #endregion
+ }
}
diff --git a/SendGrid/Tests/Transport/TestWebApi.cs b/SendGrid/Tests/Transport/TestWebApi.cs
index 5e09b9d..ecb1ad8 100644
--- a/SendGrid/Tests/Transport/TestWebApi.cs
+++ b/SendGrid/Tests/Transport/TestWebApi.cs
@@ -9,76 +9,89 @@ using SendGrid;
namespace Transport
{
- [TestFixture]
- internal class TestWebApi
- {
- private const string TestUsername = "username";
- private const string TestPassword = "password";
+ [TestFixture]
+ internal class TestWebApi
+ {
+ private const string TestUsername = "username";
+ private const string TestPassword = "password";
+ private const string TestApiKey = "apikey";
-
- [Test]
- public void TestFetchFileBodies()
- {
- var webApi = new Web(new NetworkCredential(TestUsername, TestPassword));
- var message = new Mock<ISendGrid>();
- var attachments = new[] {"foo", "bar", "foobar"};
- message.SetupProperty(foo => foo.Attachments, null);
- var result = webApi.FetchFileBodies(message.Object);
- Assert.AreEqual(0, result.Count);
+ [Test]
+ public void TestFetchFileBodies()
+ {
+ TestFetchFileBodiesHelper(new Web(new NetworkCredential(TestUsername, TestPassword)));
+ TestFetchFileBodiesHelper(new Web(TestApiKey));
+ }
- message.SetupProperty(foo => foo.Attachments, attachments);
- result = webApi.FetchFileBodies(message.Object);
- Assert.AreEqual(attachments.Count(), result.Count);
- for (var index = 0; index < attachments.Length; index++)
- Assert.AreEqual(result[index].Value.Name, attachments[index]);
- }
+ public void TestFetchFileBodiesHelper(Web webApi)
+ {
+ // Test using credentials
+ var message = new Mock<ISendGrid>();
+ var attachments = new[] {"foo", "bar", "foobar"};
+ message.SetupProperty(foo => foo.Attachments, null);
+ var result = webApi.FetchFileBodies(message.Object);
+ Assert.AreEqual(0, result.Count);
- [Test]
- public void TestFetchFormParams()
- {
- // Test Variables
- const string toAddress = "foobar@outlook.com";
- const string ccAddress = "cc@outlook.com";
- const string bcc1Address = "bcc1@outlook.com";
- const string bcc2Address = "bcc2@outlook.com";
- MailAddress[] bccAddresses = {new MailAddress(bcc1Address), new MailAddress(bcc2Address)};
- const string fromAddress = "test@outlook.com";
- const string subject = "Test Subject";
- const string textBody = "Test Text Body";
- const string htmlBody = "<p>Test HTML Body</p>";
- const string headerKey = "headerkey";
- var testHeader = new Dictionary<string, string> { { headerKey, "headervalue" } };
- const string categoryName = "Example Category";
+ message.SetupProperty(foo => foo.Attachments, attachments);
+ result = webApi.FetchFileBodies(message.Object);
+ Assert.AreEqual(attachments.Count(), result.Count);
+ for (var index = 0; index < attachments.Length; index++)
+ Assert.AreEqual(result[index].Value.Name, attachments[index]);
+ }
- var message = new SendGridMessage();
- message.AddTo(toAddress);
+ [Test]
+ public void TestFetchFormParams()
+ {
+ TestFetchFormParamsHelper(new Web(new NetworkCredential(TestUsername, TestPassword)), true);
+ TestFetchFormParamsHelper(new Web(TestApiKey), false);
+ }
+
+ public void TestFetchFormParamsHelper(Web webApi, bool credentials)
+ {
+ // Test Variables
+ const string toAddress = "foobar@outlook.com";
+ const string ccAddress = "cc@outlook.com";
+ const string bcc1Address = "bcc1@outlook.com";
+ const string bcc2Address = "bcc2@outlook.com";
+ MailAddress[] bccAddresses = {new MailAddress(bcc1Address), new MailAddress(bcc2Address)};
+ const string fromAddress = "test@outlook.com";
+ const string subject = "Test Subject";
+ const string textBody = "Test Text Body";
+ const string htmlBody = "<p>Test HTML Body</p>";
+ const string headerKey = "headerkey";
+ var testHeader = new Dictionary<string, string> { { headerKey, "headervalue" } };
+ const string categoryName = "Example Category";
+
+ var message = new SendGridMessage();
+ message.AddTo(toAddress);
message.AddCc(ccAddress);
- message.Bcc = bccAddresses;
- message.From = new MailAddress(fromAddress);
- message.Subject = subject;
- message.Text = textBody;
- message.Html = htmlBody;
- message.AddHeaders(testHeader);
- message.Header.SetCategory(categoryName);
+ message.Bcc = bccAddresses;
+ message.From = new MailAddress(fromAddress);
+ message.Subject = subject;
+ message.Text = textBody;
+ message.Html = htmlBody;
+ message.AddHeaders(testHeader);
+ message.Header.SetCategory(categoryName);
- var webApi = new Web(new NetworkCredential(TestUsername, TestPassword));
- var result = webApi.FetchFormParams(message);
- Assert.True(result.Any(r => r.Key == "api_user" && r.Value == TestUsername));
- Assert.True(result.Any(r => r.Key == "api_key" && r.Value == TestPassword));
- Assert.True(result.Any(r => r.Key == "to[]" && r.Value == toAddress));
+ var result = webApi.FetchFormParams(message);
+ if (credentials)
+ {
+ Assert.True(result.Any(r => r.Key == "api_user" && r.Value == TestUsername));
+ Assert.True(result.Any(r => r.Key == "api_key" && r.Value == TestPassword));
+ }
+ Assert.True(result.Any(r => r.Key == "to[]" && r.Value == toAddress));
Assert.True(result.Any(r => r.Key == "cc[]" && r.Value == ccAddress));
Assert.True(result.Any(r => r.Key == "bcc[]" && r.Value == bcc1Address));
Assert.True(result.Any(r => r.Key == "bcc[]" && r.Value == bcc2Address));
- Assert.True(result.Any(r => r.Key == "from" && r.Value == fromAddress));
- Assert.True(result.Any(r => r.Key == "subject" && r.Value == subject));
- Assert.True(result.Any(r => r.Key == "text" && r.Value == textBody));
- Assert.True(result.Any(r => r.Key == "html" && r.Value == htmlBody));
- Assert.True(
- result.Any(
- r => r.Key == "headers" && r.Value == String.Format("{{\"{0}\":\"{1}\"}}", headerKey, testHeader[headerKey])));
- Assert.True(
- result.Any(r => r.Key == "x-smtpapi" && r.Value == String.Format("{{\"category\" : \"{0}\"}}", categoryName)));
- }
-
- }
-} \ No newline at end of file
+ Assert.True(result.Any(r => r.Key == "from" && r.Value == fromAddress));
+ Assert.True(result.Any(r => r.Key == "subject" && r.Value == subject));
+ Assert.True(result.Any(r => r.Key == "text" && r.Value == textBody));
+ Assert.True(result.Any(r => r.Key == "html" && r.Value == htmlBody));
+ Assert.True(
+ result.Any(
+ r => r.Key == "headers" && r.Value == String.Format("{{\"{0}\":\"{1}\"}}", headerKey, testHeader[headerKey])));
+ Assert.True(
+ result.Any(r => r.Key == "x-smtpapi" && r.Value == String.Format("{{\"category\" : \"{0}\"}}", categoryName)));
+ }
+ }
+}