Last active
August 29, 2015 14:19
-
-
Save romeshniriella/328de432e4f86e4ed5d9 to your computer and use it in GitHub Desktop.
Bing-Mail Easy Post Api - Version 1.3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class SessionObject | |
{ | |
public string user { get; set; } | |
public string account { get; set; } | |
public string session_id { get; set; } | |
} | |
public class BingMailConfigOptions | |
{ | |
public string AuthUserName { get; set; } | |
public string AuthPassword { get; set; } | |
public string Account { get; set; } | |
public string Proxy { get; set; } | |
public string VerifyCertificate { get; set; } | |
} | |
/// <summary> | |
/// Version 1.3 | |
/// </summary> | |
public class BingMailEasyPostApi | |
{ | |
private static ILogger _log; | |
// session control endpoints | |
private const string SessionIdUri = "publicinterface/get_session_id.json?account={0}"; | |
private const string SessionEndUri = "publicinterface/end_session.json?session_id={0}"; | |
// upload endpoint prefix | |
private const string UploadUri = "direct_upload/{0}/{1}"; | |
private readonly List<string> _easypostHosts = new List<string>() | |
{ | |
"https://easymail.com/", | |
"https://bingmail.com.au/", | |
"https://alt.easymail.com/" | |
}; | |
private readonly BingMailConfigOptions _configOptions; | |
public BingMailEasyPostApi(BingMailConfigOptions configOptions) | |
{ | |
_configOptions = configOptions; | |
_log = CommonServices.GetLogger<BingMailEasyPostApi>(); | |
} | |
public string Send(string metaDataFile, string pathToFile) | |
{ | |
_log.Trace("Creating a new session"); | |
var sessionId = GetSessionId(); | |
_log.Trace("RCVD Session ID : " + sessionId); | |
_log.Trace("Uploading metadata file : " + metaDataFile); | |
Upload(sessionId, metaDataFile); | |
_log.Trace("Uploading invoice file : " + pathToFile); | |
Upload(sessionId, pathToFile); | |
_log.Trace("Ending Session : " + sessionId); | |
return EndSession(sessionId); | |
} | |
private string GetSessionId() | |
{ | |
_log.Trace("Trying to get the session id"); | |
string sessionId = ""; | |
Uri uri = new Uri(_easypostHosts[0] + SessionIdUri.FormatWith(_configOptions.Account)); | |
DigestAuthFixer.Create(uri.GetLeftPart(UriPartial.Authority), _configOptions.AuthUserName, _configOptions.AuthPassword); | |
sessionId = DigestAuthFixer.GrabResponse(uri.PathAndQuery); | |
_log.Info("Session Info: " + sessionId); | |
var obj = JsonConvert.DeserializeObject<SessionObject>(sessionId); | |
return obj.session_id; | |
} | |
private string EndSession(string sessionId) | |
{ | |
_log.Trace("Trying to end the session"); | |
var responseStr = ""; | |
Uri uri = new Uri(_easypostHosts[0] + SessionEndUri.FormatWith(sessionId)); | |
var request = GetWebRequest(uri); | |
var response = (HttpWebResponse)request.GetResponse(); | |
if (response.StatusCode == HttpStatusCode.OK) | |
{ | |
var stream = response.GetResponseStream(); | |
if (stream != null) | |
{ | |
var reader = new StreamReader(stream); | |
responseStr = reader.ReadToEnd(); | |
reader.Close(); | |
} | |
} | |
response.Close(); | |
_log.Info("End Response: " + responseStr); | |
return responseStr; | |
} | |
private WebRequest GetWebRequest(Uri uri) | |
{ | |
WebRequest request = WebRequest.Create(uri); | |
var credentialCache = GetCredentialCache(uri, _configOptions); | |
request.Credentials = credentialCache; | |
request.PreAuthenticate = true; | |
return request; | |
} | |
public static CredentialCache GetCredentialCache(Uri uri, BingMailConfigOptions options) | |
{ | |
var credentialCache = new CredentialCache | |
{ | |
{ | |
new Uri(uri.GetLeftPart(UriPartial.Authority)), | |
"Digest", | |
new NetworkCredential(options.AuthUserName, options.AuthPassword) | |
} | |
}; | |
return credentialCache; | |
} | |
private void Upload(string sessionId, string filePath) | |
{ | |
_log.Trace("Trying to upload the file: " + filePath); | |
var file = new FileInfo(filePath); | |
if (file.Exists) | |
{ | |
var content = ""; | |
var fileName = file.Name.Replace("_", "") | |
.Replace("-", "") | |
.Replace("[", "") | |
.Replace("]", ""); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// extracted from http://stackoverflow.com/a/3117042/959245 | |
// mopdified to support whatever HTTP methods. | |
// PUT in my case | |
public static class DigestAuthFixer | |
{ | |
private static ILogger _log; | |
private static string _host; | |
private static string _user; | |
private static string _password; | |
private static string _realm; | |
private static string _nonce; | |
private static string _qop; | |
private static string _cnonce; | |
private static string _opaque; | |
private static DateTime _cnonceDate; | |
private static int _nc = 0; | |
private static bool isInitialized = false; | |
public static void Create(string host, string user, string password) | |
{ | |
_log = CommonServices.GetLogger("DigestAuthFixer"); | |
_host = host; | |
_user = user; | |
_password = password; | |
isInitialized = true; | |
} | |
private static string CalculateMd5Hash( | |
string input) | |
{ | |
var inputBytes = Encoding.ASCII.GetBytes(input); | |
var hash = MD5.Create().ComputeHash(inputBytes); | |
var sb = new StringBuilder(); | |
foreach (var b in hash) | |
sb.Append(b.ToString("x2")); | |
return sb.ToString(); | |
} | |
private static string GrabHeaderVar( | |
string varName, | |
string header) | |
{ | |
_log.Trace("Gonna grab header : " + varName); | |
var regHeader = new Regex(string.Format(@"{0}=""([^""]*)""", varName)); | |
var matchHeader = regHeader.Match(header); | |
if (matchHeader.Success) | |
return matchHeader.Groups[1].Value; | |
return string.Empty; | |
} | |
// http://en.wikipedia.org/wiki/Digest_access_authentication | |
public static string GetDigestHeader( | |
string dir, string method = "GET") | |
{ | |
_nc = _nc + 1; | |
var ha1 = CalculateMd5Hash(string.Format("{0}:{1}:{2}", _user, _realm, _password)); | |
var ha2 = CalculateMd5Hash(string.Format("{0}:{1}", method, dir)); | |
var digestResponse = | |
CalculateMd5Hash(string.Format("{0}:{1}:{2:00000000}:{3}:{4}:{5}", ha1, _nonce, _nc, _cnonce, _qop, ha2)); | |
return string.Format("Digest username=\"{0}\", realm=\"{1}\", nonce=\"{2}\", uri=\"{3}\", " + | |
"algorithm=MD5, response=\"{4}\", qop=\"{5}\", nc=\"{6:00000000}\", cnonce=\"{7}\"{8}", | |
_user, _realm, _nonce, dir, digestResponse, _qop, _nc, _cnonce, _opaque.IsNotBlank() ? ", opaque=\"{0}\"".FormatWith(_opaque) : ""); | |
} | |
public static string GrabResponse( | |
string dir, string method = "GET") | |
{ | |
if (!isInitialized) | |
{ | |
throw new InvalidOperationException("Not initialized"); | |
} | |
var url = _host + dir; | |
var uri = new Uri(url); | |
var request = (HttpWebRequest)WebRequest.Create(uri); | |
// If we've got a recent Auth header, re-use it! | |
if (!string.IsNullOrEmpty(_cnonce) && | |
DateTime.Now.Subtract(_cnonceDate).TotalHours < 1.0) | |
{ | |
request.Headers.Add("Authorization", GetDigestHeader(dir, method)); | |
} | |
HttpWebResponse response; | |
try | |
{ | |
response = (HttpWebResponse)request.GetResponse(); | |
} | |
catch (WebException ex) | |
{ | |
// Try to fix a 401 exception by adding a Authorization header | |
if (ex.Response == null || ((HttpWebResponse)ex.Response).StatusCode != HttpStatusCode.Unauthorized) | |
throw; | |
var wwwAuthenticateHeader = ex.Response.Headers["WWW-Authenticate"]; | |
_realm = GrabHeaderVar("realm", wwwAuthenticateHeader); | |
_nonce = GrabHeaderVar("nonce", wwwAuthenticateHeader); | |
_qop = GrabHeaderVar("qop", wwwAuthenticateHeader); | |
_opaque = GrabHeaderVar("opaque", wwwAuthenticateHeader); | |
_nc = 0; | |
_cnonce = new Random().Next(123400, 9999999).ToString(); | |
_cnonceDate = DateTime.Now; | |
var request2 = (HttpWebRequest)WebRequest.Create(uri); | |
request2.Headers.Add("Authorization", GetDigestHeader(dir, method)); | |
response = (HttpWebResponse)request2.GetResponse(); | |
} | |
var reader = new StreamReader(response.GetResponseStream()); | |
return reader.ReadToEnd(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class InvoiceOperationsEngine : IInvoiceOperationsEngine | |
{ | |
private static ILogger _log; | |
// -- ctor -- | |
public void SendMailout(InvoiceMailout mailout) | |
{ | |
//.... | |
var metaData = new MailDocumentMetaData(mailout) | |
{ | |
CustomerEmail = sysSettings.NotificationEmail | |
}; | |
var fileName = file.Name.Replace("_", "") | |
.Replace("-", "") | |
.Replace("[", "") | |
.Replace("]", ""); | |
var letter = new Letter() | |
{ | |
FileName = fileName | |
}; | |
letter.FillAdddress(customer, geoRepo); | |
metaData.Letters.Add(letter); | |
var metaFile = WriteMetaDataFile(metaData, invoicePath); | |
var mailer = new BingMailEasyPostApi(new BingMailConfigOptions() | |
{ | |
Account = settings.AccountCode, | |
AuthUserName = settings.UserName, | |
AuthPassword = settings.Password | |
}); | |
var response = mailer.Send(metaFile, invoicePath); | |
//.... | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class MailDocumentMetaData | |
{ | |
[JsonProperty("duplex")] | |
public bool IsDuplex { get; set; } | |
[JsonProperty("colour_model")] | |
public int ColourModel { get; set; } | |
[JsonProperty("title")] | |
public string Title { get; set; } | |
[JsonProperty("customer_email")] | |
public string CustomerEmail { get; set; } | |
[JsonProperty("confirmation_email")] | |
public bool ConfirmationEmail { get; set; } | |
[JsonProperty("department")] | |
public string Department { get; set; } | |
[JsonProperty("terminal")] | |
public string Terminal { get; set; } | |
[JsonProperty("orientation")] | |
public int Orientation { get; set; } | |
[JsonProperty("letters")] | |
public List<Letter> Letters { get; set; } | |
public MailDocumentMetaData(CustomerInvoiceMailout mailout) | |
{ | |
Letters = new List<Letter>(); | |
this.IsDuplex = mailout.IsDuplex; | |
ColourModel = mailout.ColourModel; | |
Title = mailout.Title; | |
ConfirmationEmail = mailout.EmailConfirmation; | |
Department = mailout.Department; | |
Terminal = mailout.Terminal; | |
Orientation = mailout.Orientation.ToSafeInt32(); | |
} | |
} | |
public class Letter | |
{ | |
public Letter() | |
{ | |
Postal = new List<string>(); | |
Primary = "postal"; | |
} | |
[JsonProperty("postal")] | |
public List<string> Postal { get; set; } | |
[JsonProperty("primary")] | |
public string Primary { get; set; } | |
[JsonProperty("file_name")] | |
public string FileName { get; set; } | |
internal void FillAdddress(Customer customer, IReadOnlyRepository<GeographicLocation> geoRepo) | |
{ | |
var locality = ""; | |
if (customer.BillingLocality != null) | |
{ | |
var geo = geoRepo.Get(customer.BillingLocality.Value); | |
locality = geo.Name.Replace(",",""); | |
} | |
Postal.AddIf(s => customer.BillingName.IsNotBlank(), customer.BillingName); | |
Postal.AddIf(s => customer.BillingAddressA.IsNotBlank(), customer.BillingAddressA); | |
Postal.AddIf(s => customer.BillingAddressB.IsNotBlank(), customer.BillingAddressB); | |
Postal.AddIf(s => customer.BillingAddressC.IsNotBlank(), customer.BillingAddressC); | |
Postal.AddIf(s => locality.IsNotBlank(), locality); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment