diff options
Diffstat (limited to 'SendGrid/SendGridMail')
-rw-r--r-- | SendGrid/SendGridMail/Mail.csproj | 11 | ||||
-rwxr-xr-x | SendGrid/SendGridMail/Properties/AssemblyInfo.cs | 4 | ||||
-rwxr-xr-x | SendGrid/SendGridMail/SendGrid.cs | 1 | ||||
-rwxr-xr-x | SendGrid/SendGridMail/StreamedFileBody.cs | 2 | ||||
-rw-r--r--[-rwxr-xr-x] | SendGrid/SendGridMail/Transport/Web.cs | 349 | ||||
-rwxr-xr-x | SendGrid/SendGridMail/Utils.cs | 14 | ||||
-rw-r--r-- | SendGrid/SendGridMail/packages.config | 4 |
7 files changed, 203 insertions, 182 deletions
diff --git a/SendGrid/SendGridMail/Mail.csproj b/SendGrid/SendGridMail/Mail.csproj index b85ec5e..7744b73 100644 --- a/SendGrid/SendGridMail/Mail.csproj +++ b/SendGrid/SendGridMail/Mail.csproj @@ -30,6 +30,10 @@ <WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="RestSharp">
+ <HintPath>..\packages\RestSharp.104.1\lib\net4\RestSharp.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net" />
@@ -41,10 +45,6 @@ <Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
- <Reference Include="CodeScales.Http">
- <HintPath>lib\CodeScales.Http.dll</HintPath>
- <Private>False</Private>
- </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Header.cs" />
@@ -52,7 +52,6 @@ <Compile Include="ISendGrid.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SendGrid.cs" />
- <Compile Include="StreamedFileBody.cs" />
<Compile Include="Transport\ITransport.cs" />
<Compile Include="Transport\Web.cs" />
<Compile Include="Transport\SMTP.cs" />
@@ -67,6 +66,6 @@ </Target>
-->
<ItemGroup>
- <EmbeddedResource Include="lib\CodeScales.Http.dll" />
+ <None Include="packages.config" />
</ItemGroup>
</Project>
\ No newline at end of file diff --git a/SendGrid/SendGridMail/Properties/AssemblyInfo.cs b/SendGrid/SendGridMail/Properties/AssemblyInfo.cs index c64fbda..1660c37 100755 --- a/SendGrid/SendGridMail/Properties/AssemblyInfo.cs +++ b/SendGrid/SendGridMail/Properties/AssemblyInfo.cs @@ -41,5 +41,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.2.0")]
-[assembly: AssemblyFileVersion("1.0.2.0")]
+[assembly: AssemblyVersion("1.1.0.0")]
+[assembly: AssemblyFileVersion("1.1.0.0")]
diff --git a/SendGrid/SendGridMail/SendGrid.cs b/SendGrid/SendGridMail/SendGrid.cs index 3f2878f..0ee7079 100755 --- a/SendGrid/SendGridMail/SendGrid.cs +++ b/SendGrid/SendGridMail/SendGrid.cs @@ -310,6 +310,7 @@ namespace SendGridMail {
MemoryStream ms = new MemoryStream();
stream.CopyTo(ms);
+ ms.Seek(0,SeekOrigin.Begin);
StreamedAttachments[name] = ms;
}
diff --git a/SendGrid/SendGridMail/StreamedFileBody.cs b/SendGrid/SendGridMail/StreamedFileBody.cs index 50d218c..faa9d59 100755 --- a/SendGrid/SendGridMail/StreamedFileBody.cs +++ b/SendGrid/SendGridMail/StreamedFileBody.cs @@ -3,8 +3,6 @@ using System.Collections.Generic; using System.IO;
using System.Linq;
using System.Text;
-using CodeScales.Http.Entity.Mime;
-using CodeScales.Http.Network;
namespace SendGridMail
{
diff --git a/SendGrid/SendGridMail/Transport/Web.cs b/SendGrid/SendGridMail/Transport/Web.cs index 7015653..3395bdd 100755..100644 --- a/SendGrid/SendGridMail/Transport/Web.cs +++ b/SendGrid/SendGridMail/Transport/Web.cs @@ -1,173 +1,178 @@ -using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Text;
+using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; using System.Xml;
-using CodeScales.Http;
-using CodeScales.Http.Entity;
-using CodeScales.Http.Entity.Mime;
-using CodeScales.Http.Methods;
-
-namespace SendGridMail.Transport
-{
- public class Web : ITransport
- {
- #region Properties
- public const String Endpoint = "http://sendgrid.com/api/mail.send";
- public const String JsonFormat = "json";
- public const String XmlFormat = "xml";
-
- private readonly NetworkCredential _credentials;
- private readonly String _restEndpoint;
- private readonly String _format;
- #endregion
-
- /// <summary>
- /// Factory method for Web transport of sendgrid messages
- /// </summary>
- /// <param name="credentials">SendGrid credentials for sending mail messages</param>
- /// <param name="url">The uri of the Web endpoint</param>
- /// <returns>New instance of the transport mechanism</returns>
- public static Web GetInstance(NetworkCredential credentials, String url = Endpoint)
- {
- return new Web(credentials, url);
- }
-
- /// <summary>
- /// Creates a new Web interface for sending mail. Preference is using the Factory method.
- /// </summary>
- /// <param name="credentials">SendGrid user parameters</param>
- /// <param name="url">The uri of the Web endpoint</param>
- internal Web(NetworkCredential credentials, String url = Endpoint)
- {
- _credentials = credentials;
-
- _format = XmlFormat;
- _restEndpoint = url + "." + _format;
- }
-
- /// <summary>
- /// Delivers a message over SendGrid's Web interface
- /// </summary>
- /// <param name="message"></param>
- public void Deliver(ISendGrid message)
- {
- MultipartEntity multipartEntity;
- HttpPost postMethod;
-
- var client = InitializeTransport(out multipartEntity, out postMethod);
- AttachFormParams(message, multipartEntity);
- AttachFiles(message, multipartEntity);
- var response = client.Execute(postMethod);
- CheckForErrors(response);
- }
-
- #region Support Methods
-
- internal HttpClient InitializeTransport(out MultipartEntity multipartEntity, out HttpPost postMethod)
- {
- var client = new HttpClient();
- postMethod = new HttpPost(new Uri(_restEndpoint));
-
- multipartEntity = new MultipartEntity();
- postMethod.Entity = multipartEntity;
- return client;
- }
-
- private void AttachFormParams(ISendGrid message, MultipartEntity multipartEntity)
- {
- var formParams = FetchFormParams(message);
- formParams.ForEach(kvp => multipartEntity.AddBody(new StringBody(Encoding.UTF8, kvp.Key, kvp.Value)));
- }
-
- private void AttachFiles(ISendGrid message, MultipartEntity multipartEntity)
- {
- var files = FetchFileBodies(message); - files.ForEach(kvp => multipartEntity.AddBody(new FileBody("files[" + Path.GetFileName(kvp.Key) + "]", Path.GetFileName(kvp.Key), kvp.Value)));
-
- var streamingFiles = FetchStreamingFileBodies(message);
- streamingFiles.ForEach(kvp => multipartEntity.AddBody(new StreamedFileBody(kvp.Value, kvp.Key))); - }
-
- private void CheckForErrors(CodeScales.Http.Methods.HttpResponse response)
- {
- var status = EntityUtils.ToString(response.Entity);
- var stream = new MemoryStream(Encoding.UTF8.GetBytes(status));
-
- using (var reader = XmlReader.Create(stream))
- {
- while (reader.Read())
- {
- if (reader.IsStartElement())
- {
- switch (reader.Name)
- {
- case "result":
- break;
- case "message": // success
- bool errors = reader.ReadToNextSibling("errors");
- if (errors)
- throw new ProtocolViolationException(status);
- else
- return;
- case "error": // failure
- throw new ProtocolViolationException(status);
- default:
- throw new ArgumentException("Unknown element: " + reader.Name);
- }
- }
- }
- }
- }
-
- 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.AsJson())
- };
- 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.Bcc != null)
- {
- result = result.Concat(message.Bcc.ToList().Select(a => new KeyValuePair<String, String>("bcc[]", a.Address)))
- .ToList();
- }
- if(message.Cc != null)
- {
- result = result.Concat(message.Cc.ToList().Select(a => new KeyValuePair<String, String>("cc[]", a.Address)))
- .ToList();
- }
- return result.Where(r => !String.IsNullOrEmpty(r.Value)).ToList();
- }
-
- internal List<KeyValuePair<String, MemoryStream>> FetchStreamingFileBodies(ISendGrid message)
- {
- return message.StreamedAttachments.Select(kvp => kvp).ToList();
- }
-
- internal List<KeyValuePair<String, FileInfo>> FetchFileBodies(ISendGrid message)
- {
- if(message.Attachments == null)
- return new List<KeyValuePair<string, FileInfo>>();
- return message.Attachments.Select(name => new KeyValuePair<String, FileInfo>(name, new FileInfo(name))).ToList();
- }
-
- #endregion
- }
-}
+using RestSharp; + +namespace SendGridMail.Transport +{ + public class Web : ITransport + { + #region Properties + //TODO: Make this configurable + public const String BaseURl = "https://sendgrid.com/api/"; + public const String Endpoint = "mail.send"; + public const String JsonFormat = "json"; + public const String XmlFormat = "xml"; + + private readonly NetworkCredential _credentials; + private readonly String _restEndpoint; + private readonly String _format; + #endregion + + /// <summary> + /// Factory method for Web transport of sendgrid messages + /// </summary> + /// <param name="credentials">SendGrid credentials for sending mail messages</param> + /// <param name="url">The uri of the Web endpoint</param> + /// <returns>New instance of the transport mechanism</returns> + public static Web GetInstance(NetworkCredential credentials, String url = Endpoint) + { + return new Web(credentials, url); + } + + /// <summary> + /// Creates a new Web interface for sending mail. Preference is using the Factory method. + /// </summary> + /// <param name="credentials">SendGrid user parameters</param> + /// <param name="url">The uri of the Web endpoint</param> + internal Web(NetworkCredential credentials, String url = Endpoint) + { + _credentials = credentials; + + _format = XmlFormat; + _restEndpoint = url + "." + _format; + } + + /// <summary> + /// Delivers a message over SendGrid's Web interface + /// </summary> + /// <param name="message"></param> + public void Deliver(ISendGrid message) + { + var client = new RestClient(BaseURl); + var request = new RestRequest(Endpoint + ".xml", Method.POST); + AttachFormParams(message, request); + AttachFiles(message, request); + var response = client.Execute(request); + CheckForErrors(response); + } + + #region Support Methods + private void AttachFormParams(ISendGrid message, RestRequest request) + { + var formParams = FetchFormParams(message); + formParams.ForEach(kvp => request.AddParameter(kvp.Key, kvp.Value)); + } + + private void AttachFiles (ISendGrid message, RestRequest request) + { + //TODO: think the files are being sent in the POST data... but we need to add them as params as well + + var files = FetchFileBodies (message); + files.ForEach (kvp => request.AddFile ("files[" + Path.GetFileName (kvp.Key) + "]", kvp.Value.FullName)); + + var streamingFiles = FetchStreamingFileBodies(message); + foreach (KeyValuePair<string, MemoryStream> file in streamingFiles) { + var name = file.Key; + var stream = file.Value; + var writer = new Action<Stream>( + delegate(Stream s) + { + stream.CopyTo(s); + } + ); + + request.AddFile("files[" + name + "]", writer, name); + } + } + + private void CheckForErrors (IRestResponse response) + { + //transport error + if (response.ResponseStatus == ResponseStatus.Error) { + throw new Exception(response.ErrorMessage); + } + + //TODO: check for HTTP errors... don't throw exceptions just pass info along? + var content = response.Content; + var stream = new MemoryStream(Encoding.UTF8.GetBytes(content)); + + using (var reader = XmlReader.Create(stream)) + { + while (reader.Read()) + { + if (reader.IsStartElement()) + { + switch (reader.Name) + { + case "result": + break; + case "message": // success + bool errors = reader.ReadToNextSibling("errors"); + if (errors) + throw new ProtocolViolationException(content); + else + return; + case "error": // failure + throw new ProtocolViolationException(content); + default: + throw new ArgumentException("Unknown element: " + reader.Name); + } + } + } + } + } + + 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.AsJson()) + }; + 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.Bcc != null) + { + result = result.Concat(message.Bcc.ToList().Select(a => new KeyValuePair<String, String>("bcc[]", a.Address))) + .ToList(); + } + if(message.Cc != null) + { + result = result.Concat(message.Cc.ToList().Select(a => new KeyValuePair<String, String>("cc[]", a.Address))) + .ToList(); + } + return result.Where(r => !String.IsNullOrEmpty(r.Value)).ToList(); + } + + internal List<KeyValuePair<String, MemoryStream>> FetchStreamingFileBodies(ISendGrid message) + { + return message.StreamedAttachments.Select(kvp => kvp).ToList(); + } + + internal List<KeyValuePair<String, FileInfo>> FetchFileBodies(ISendGrid message) + { + if(message.Attachments == null) + return new List<KeyValuePair<string, FileInfo>>(); + return message.Attachments.Select(name => new KeyValuePair<String, FileInfo>(name, new FileInfo(name))).ToList(); + } + + #endregion + } +} diff --git a/SendGrid/SendGridMail/Utils.cs b/SendGrid/SendGridMail/Utils.cs index 31fe92f..c6f4386 100755 --- a/SendGrid/SendGridMail/Utils.cs +++ b/SendGrid/SendGridMail/Utils.cs @@ -28,5 +28,19 @@ namespace SendGridMail return "{"+String.Join(",",dic.Select(kvp => Serialize(kvp.Key) + ":" + Serialize(kvp.Value)))+"}";
}
+ public static byte[] ReadFully(Stream input)
+ {
+ byte[] buffer = new byte[16*1024];
+ using (MemoryStream ms = new MemoryStream())
+ {
+ int read;
+ while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
+ {
+ ms.Write(buffer, 0, read);
+ }
+ return ms.ToArray();
+ }
+ }
+
}
}
diff --git a/SendGrid/SendGridMail/packages.config b/SendGrid/SendGridMail/packages.config new file mode 100644 index 0000000..6b04fa8 --- /dev/null +++ b/SendGrid/SendGridMail/packages.config @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="RestSharp" version="104.1" targetFramework="net40" />
+</packages>
\ No newline at end of file |