如何在 .net 中处理 Mandrill WebHooks

Posted

技术标签:

【中文标题】如何在 .net 中处理 Mandrill WebHooks【英文标题】:How To Handle Mandrill WebHooks in .net 【发布时间】:2014-09-01 23:13:42 【问题描述】:

我是一名试图与山魈一起工作的学生,老实说,我不知道自己在做什么。 我可以在 .net 中使用 mandrill 发送电子邮件 我现在想做的是使用 webhook 来捕获退回的电子邮件,一旦我完成了可能会更多。

这是我到目前为止的代码(来自互联网)

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);

然后我就有了这个

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; 

谁能告诉我如何处理 mandrill webhook 响应。 它在 json 中。

我以前从未做过这样的事情。我错过了很多代码吗? json 是作为文件还是原始代码传入?

谢谢各位。 我真的很感激。

【问题讨论】:

【参考方案1】:

我在 VS 中将 Mandrill Webhook 处理作为 API 项目运行,这就是我启动和运行它的方式:

    [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://***.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";
    

然后,我获取了“mandrill_event”的记录(和未记录)JSON 参数并使用json2csharp.com 生成C# 属性。我创建了一个名为“MandrillEvent.cs”的类并将它们放在:

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();
        
    

您现在将“mandrill_events”JSON 对象作为功能 C# 对象!这是帮助还是您需要更多说明/帮助?

【讨论】:

嗨.. hopper... 从现在开始,我一直在寻找类似的代码。请问有没有可能帮我解决这个问题? 我当然可以尝试,Athar。怎么了? 谢谢@Hopper...我已经以某种方式解决了它。如果您可以分享您的代码以与 Mandrill 交互,那就太好了。不然我就得自己写了 这个解决方案曾经对我有用,但突然停止了。其他人有过这种经历吗?【参考方案2】:

似乎所有人给出的代码都是错误的,就好像我们使用 request.form 和任何键一样,我们根本不需要替换。

代码如下:

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...

在这里您可以看到转换是映射到 WebHookEvent 而不是 MailEvent,如下所示。

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

希望这对其他人有所帮助。

【讨论】:

【参考方案3】:

您还可以使用 System.Json 将 json 字符串解析为使用 JsonValue.Parse() 的通用 JsonValue。

您所要做的就是稍微修改一下 Mandrill 的响应 json 以获得有效的 json 文档。

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】:

如果您使用的是 Azure http 触发函数,那么代码将如下所示:

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

如果你使用 web apis 代码会是这样的:

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

【讨论】:

以上是关于如何在 .net 中处理 Mandrill WebHooks的主要内容,如果未能解决你的问题,请参考以下文章

通过 Mandrill 使用 Elmah 发送错误电子邮件

Mandrill Mailchimp 如何在电子邮件正文中嵌入图像

MailChimp (Mandrill) for .NET 为啥电子邮件包含图像?

如何使用 Parse 和 Mandrill 发送电子邮件通知?

您将如何使用 phantomjs 通过 mandrill 发送邮件?

.NET 使用 SmtpClient 和 Mandrill SMTP 发送失败