How To Handle Mandrill WebHooks in .net

人走茶凉 提交于 2019-12-12 00:57:48

问题


I'm a student trying to work with mandrill and to be quite honest, I haven't a clue what I'm at. I'm able to send emails no problem using mandrill in .net What I want to do now is use webhooks to catch bounce emails at the moment and maybe more once I have accomplished that.

Here is the code I have so far (from the internet)

public ActionResult HandleMandrillWebhook(FormCollection fc)
    {
        string json = fc["mandrill_events"];

        var events = JsonConvert.DeserializeObject<IEnumerable<Mandrill.MailEvent>>(json);
        foreach (var mailEvent in events)
        {
            var message = mailEvent.Msg;
            // ... Do stuff with email message here...
        }

        // MUST do this or Mandrill will not accept your webhook!
        return new HttpStatusCodeResult((int)HttpStatusCode.OK);

and then I have this

public class MailEvent
{
    [JsonProperty(PropertyName = "ts")]
    public string TimeStamp { get; set; }

    [JsonProperty(PropertyName = "event")]
    public string Event { get; set; }

    [JsonProperty(PropertyName = "msg")]
    public Message Msg { get; set; }
}

public class Message
{
    [JsonProperty(PropertyName = "raw_msg")]
    public string RawMessage { get; set; }

    [JsonProperty(PropertyName = "headers")]
    public Header Header { get; set; }

    [JsonProperty(PropertyName = "text")]
    public string Text { get; set; }

    [JsonProperty(PropertyName = "html")]
    public string Html { get; set; }

    [JsonProperty(PropertyName = "from_email")]
    public string FromEmail { get; set; }

    [JsonProperty(PropertyName = "from_name")]
    public string FromName { get; set; }

    // Not sure why Mandrill sends an array of arrays here...
    [JsonProperty(PropertyName = "to")]
    public string[][] To { get; set; }

    [JsonProperty(PropertyName = "email")]
    public string Email { get; set; }

    [JsonProperty(PropertyName = "subject")]
    public string Subject { get; set; }

    [JsonProperty(PropertyName = "tags")]
    public string[] Tags { get; set; }

    [JsonProperty(PropertyName = "sender")]
    public string Sender { get; set; }

    [JsonProperty(PropertyName = "dkim")]
    public DKIM DKIM { get; set; }

    [JsonProperty(PropertyName = "spf")]
    public SPF SPF { get; set; }

    [JsonProperty(PropertyName = "spam_report")]
    public SpamReport SpamReport { get; set; }
}

[JsonDictionary()]
public class Header : Dictionary<string, object>
{
    // Need to find a nicer way of doing this... Dictionary<string, object> is kinda dumb
}

public class SpamReport
{
    [JsonProperty(PropertyName = "score")]
    public decimal Score { get; set; }

    [JsonProperty(PropertyName = "matched_rules")]
    public SpamRule[] MatchedRules { get; set; }
}

public class SpamRule
{
    [JsonProperty(PropertyName = "name")]
    public string Name { get; set; }

    [JsonProperty(PropertyName = "score")]
    public decimal Score { get; set; }

    [JsonProperty(PropertyName = "description")]
    public string Description { get; set; }
}

public class DKIM
{
    [JsonProperty(PropertyName = "signed")]
    public bool Signed { get; set; }

    [JsonProperty(PropertyName = "valid")]
    public bool Valid { get; set; }
}

public class SPF
{
    [JsonProperty(PropertyName = "result")]
    public string Result { get; set; }

    [JsonProperty(PropertyName = "detail")]
    public string Detail { get; set; }
}

Could somebody please show me how to process the mandrill webhook response then. Its in json.

I have never done anything like this before. Am I missing much code? Is json passed in as a file or raw code?

Thanks guys. I really appreciate it.


回答1:


I am running my Mandrill Webhook handling as an API project in VS and this is how I am have gotten it up and running:

    [HttpPost]
    public string Post()
    {
        /* Every Mandrill webhook uses the same general data format, regardless of the event type. 
         * The webhook request is a standard POST request with a single parameter (currently) - 'mandrill_events'. */

        string validJson = HttpContext.Current.Request.Form["mandrill_events"].Replace("mandrill_events=", ""); //"mandrill_events=" is not valid JSON. If you take that out you should be able to parse it. //http://stackoverflow.com/questions/24521326/deserializing-mandrillapp-webhook-response
        List<MandrillEvent> mandrillEventList = JsonConvert.DeserializeObject<List<MandrillEvent>>(validJson);

        foreach (MandrillEvent mandrillEvent in mandrillEventList)
        {
            if (mandrillEvent.msg.email != null)
            {
                DataLayer.ReportingData.EmailSave(mandrillEvent); //Saves MandrillEvent email to database and sets a messageId for datalayer
            }
        } 

        foreach (MandrillEvent mandrillEvent in mandrillEventList)
        {
            DataLayer.ReportingData.MandrillEventSave(mandrillEvent); //Saves MandrillEvent object to database
        }

        return "DONE";
    }

I then took the documented (and undocumented) JSON parameters of "mandrill_event" and used json2csharp.com to generate the C# properties. I created a class called "MandrillEvent.cs" and put these within:

public class SmtpEvent
    {
        public int ts { get; set; }
        public DateTime SmtpTs { get; set; }
        public string type { get; set; }
        public string diag { get; set; }
        public string source_ip { get; set; }
        public string destination_ip { get; set; }
        public int size { get; set; }
        public int smtpId { get; set; } //added for datalayer
    }

    public class Msg
    {
        public int ts { get; set; }
        public DateTime MsgTs { get; set; }
        public string _id { get; set; }
        public string state { get; set; }
        public string subject { get; set; }
        public string email { get; set; }
        public List<object> tags { get; set; }
        public List<object> opens { get; set; } //an array of containing an item for each time the message was opened. Each open includes the following keys: "ts", "ip", "location", "ua"
        public List<object> clicks { get; set; } //an array containing an item for each click recorded for the message. Each item contains the following: "ts", "url"
        public List<SmtpEvent> smtp_events { get; set; }
        public List<object> resends { get; set; } //not currently documented on http://help.mandrill.com/entries/58303976-Message-Event-Webhook-format
        public string _version { get; set; }
        public string diag { get; set; } //for bounced and soft-bounced messages, provides the specific SMTP response code and bounce description, if any, received from the remote server
        public int bgtools_code { get; set; } //Is it this? for bounced and soft-bounced messages, a short description of the bounce reason such as bad_mailbox or invalid_domain. (not currently documented but in JSON response)
        public string sender { get; set; }
        public object template { get; set; }
        public string bounce_description { get; set; }

        public Msg()
        {
            tags = new List<object>();
            opens = new List<object>();
            clicks = new List<object>();
            smtp_events = new List<SmtpEvent>();
            smtp_events.Add(new SmtpEvent());
            resends = new List<object>();
        }
    }

    public class MandrillEvent
    {
        public string @event { get; set; }
        public string _id { get; set; }
        public Msg msg { get; set; }
        public int ts { get; set; }
        public DateTime MandrillEventTs { get; set; }
        public int messageId { get; set; } //added for datalayer
        public List<string> SingleMandrillEventData { get; set; } //added for Reporting

        public MandrillEvent()
        {
            SingleMandrillEventData = new List<string>();
            msg = new Msg();
        }
    }

You now have your "mandrill_events" JSON object as a functioning C# object!! Did this help or do you need some more clarification/help?




回答2:


It seems the the code given by all are wrong as if we use request.form with any key then we do not require to replace at any all.

The code will be like below:

string events_json = HttpContext.Current.Request.Form["mandrill_events"];

var events = **Mandrill.Utilities.JSON.Parse<List<Mandrill.Models.WebHookEvent>>(events_json)**;
foreach (var mailEvent in events)
{
    var message = mailEvent.Msg;
    // ... Do stuff with email message here...
}

Here you can see that conversion is map to WebHookEvent not the MailEvent as below.

JsonConvert.DeserializeObject<IEnumerable<Mandrill.MailEvent>>(json)

Hope This will help other.




回答3:


You can also use System.Json to parse the json string into a generic JsonValue using JsonValue.Parse().

All you have to do is modify the response json from Mandrill a little in order to get a valid json document.

string json = HttpContext.Current.Request.Form["mandrill_events"];
json = json.Replace("mandrill_events=", "");    // Remove invalid json
json = string.Format("{{Events: {0}}}", json);  // Create valid json element
var jsonValue = JsonValue.Parse(json);

// Now you can loop through the events
foreach(var e in jsonValue["Events"])
{
    var id = (string)e.Value["_id"];
    var event_text = (string)e.Value["event"];
    // etc.
}



回答4:


If you are using Azure http trigger functions then the code will be like this:

string requestBody = await new StreamReader(req.Body, Encoding.UTF8).ReadToEndAsync();
             requestBody = requestBody.Replace("mandrill_events=", "");
              requestBody = System.Web.HttpUtility.UrlDecode(requestBody);

If you are using web apis code will be like this:

var requestBody = Request.HttpContext.Request.Form["mandrill_events"].ToString();


来源:https://stackoverflow.com/questions/24695846/how-to-handle-mandrill-webhooks-in-net

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!