We have a MailChimp List, and that List contains at least one Member. Now we can go ahead and send a Campaign.
In MailChimp, a Campaign consists of two basic parts: Content, or whatever it is you plan to email; and a List to which it will be mailed.
Content can be plain text, HTML, or a Template. (We can also create RSS-driven campaigns.) Additionally, we can specify a given Segment of a List to which we want the campaign sent; either a previously saved Segment, or a Segment we create prior to sending the Campaign and don’t save.
We can also configure the Campaign to include tracking, analytics, folders and so on.
I’m not going to cover those in this tutorial, but it’s worth mentioning that the MailChimp.NET.V3 library has support for all those features.
Create a Campaign
To create a MailChimp campaign via the API, we first instantiate, then populate the properties of, a Campaign object. Then, we call the MailChimpManager.Campaigns.AddOrUpdateAsync method.
using MailChimp.Net; using MailChimp.Net.Core; using MailChimp.Net.Models; using System; using System.Net; using System.Threading.Tasks; using System.Web.Mvc; namespace MailChimpNetDemo.Controllers { public class MailChimpCampaignController : Controller { private static MailChimpManager Manager = new MailChimpManager(); public async Task<ActionResult> Create() { var campaign = new Campaign { Type = CampaignType.Regular, Recipients = new Recipient { ListId = "f809a0eba9" }, Settings = new Setting { SubjectLine = $"Campaign created by program at {DateTime.UtcNow.ToString("s")}", Title = $"Dynamic campaign {Guid.NewGuid()}", FromName = "Doug Vanderweide", ReplyTo = "mailchimp@dougv.com" }, Tracking = new Tracking { Opens = true, HtmlClicks = true, TextClicks = true }, SocialCard = new SocialCard { ImageUrl = "http://cdn.smosh.com/sites/default/files/legacy.images/smosh-pit/122010/lolcat-link.jpg", Description = "I'm learning how to make dynamic MailChimp campaigns via the API.", Title = "Using the MailChimp API in .NET via the MailChimp.NET.V3 wrapper" }, ReportSummary = new ReportSummary(), DeliveryStatus = new DeliveryStatus() }; try { await Manager.Campaigns.AddOrUpdateAsync(campaign); return RedirectToAction("Index"); } catch (MailChimpException mce) { return new HttpStatusCodeResult(HttpStatusCode.BadGateway, mce.Message); } catch (Exception ex) { return new HttpStatusCodeResult(HttpStatusCode.ServiceUnavailable, ex.Message); } } } }
Note that we assign the Campaign to a List. All Campaigns must belong to a List; you can’t have a “generic” Campaign.
Adding dynamic Content to a Campaign
With the Campaign created, we can now add content to it.
One way to do that is to specify the HTML and plain text you want to use. To do that, we create a ContentRequest object, setting its Html and PlainText properties, respectively.
We then call MailChimpManager.Content.AddOrUpdateAsync, specifying the Campaign Id and the ContentRequest object we just created.
public async Task<ActionResult> SetContentRaw() { var content = new ContentRequest { PlainText = "Hello world! I am testing Doug Vanderweide's MailChimp.NET.V3 demo, at https://www.dougv.com", Html = "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"><title>title</title></head><body><p>Hello world! I am testing Doug Vanderweide's MailChimp.NET.V3 demo, at <a href=\"https://www.dougv.com\">https://www.dougv.com</a></body></html>" }; try { await Manager.Content.AddOrUpdateAsync("d4688e21b2", content); return RedirectToAction("Detail"); } catch (MailChimpException mce) { return new HttpStatusCodeResult(HttpStatusCode.BadGateway, mce.Message); } catch (Exception ex) { return new HttpStatusCodeResult(HttpStatusCode.ServiceUnavailable, ex.Message); } }
Note that at Lines 5 and 6, I set the PlainText and HTML values for my content with strings. I could just as easily have called a TextReader / StreamReader here and picked up one or more of those values from a file:
using (var reader = File.OpenText("content-source-file.html")) { content.Html(reader.ReadToEnd()); }
Finally, note that I can set the Content of a Campaign as many times as I like, overriding previous content.
Setting Content via a Template
I expect that will be cleared up and will edit this section once it is ready.
Update a Campaign
Updating a Campaign does not alter its Content; rather, it only affects the List to which the Campaign is assigned, along with other metadata.
As with creating a Campaign, we need to provide Campaign object; in this case, including the Id of the campaign we want to alter.
However, we only need to populate the other Campaign properties that we want altered; if we don’t specify an updated value for a Campaign property, its old value will be retained.
public async Task<ActionResult> Update() { var campaign = new Campaign { Id = "d4688e21b2", Settings = new Setting { Title = $"Dynamic campaign {Guid.NewGuid()} modified {DateTime.UtcNow.ToString("s")}" } }; try { await Manager.Campaigns.AddOrUpdateAsync(campaign); return RedirectToAction("Detail"); } catch (MailChimpException mce) { return new HttpStatusCodeResult(HttpStatusCode.BadGateway, mce.Message); } catch (Exception ex) { return new HttpStatusCodeResult(HttpStatusCode.ServiceUnavailable, ex.Message); } }
Test a Campaign
Normally I would also recommend calling the Send Checklist before testing a Campaign. While I see an implementation of the Send Checklist in the MailChimp.NET.V3 library, I don’t see a public MailChimpManager method that exposes it, so I am unsure how to call it.
That said, if you run a Campaign test prior to sending, you should be able to verify that your Campaign is good to go.
With your Campaign’s Content properly set, you can test it. To do that, you’ll need at least one email address; if you want to use more (such as to ensure PlainText works OK), you provide them as a string array.
public async Task<ActionResult> Test() { try { await Manager.Campaigns.TestAsync("d4688e21b2", new CampaignTestRequest { Emails = new string[] { "foo@bar.com", "bar@foo.com" }, EmailType = "html" }); return RedirectToAction("Detail"); } catch (MailChimpException mce) { return new HttpStatusCodeResult(HttpStatusCode.BadGateway, mce.Message); } catch (Exception ex) { return new HttpStatusCodeResult(HttpStatusCode.ServiceUnavailable, ex.Message); } }
After you run your test, check the email accounts to which you sent the test; it should receive the messages shortly, and prefix the subject line with the word [Test].
Send a Campaign
And finally, the payoff: Sending a Campaign.
All we need to do is provide the MailChimpManager.Campaigns.SendAsync method the ID of our campaign.
public async Task<ActionResult> Send() { try { await Manager.Campaigns.SendAsync("d4688e21b2"); return RedirectToAction("Detail"); } catch (MailChimpException mce) { return new HttpStatusCodeResult(HttpStatusCode.BadGateway, mce.Message); } catch (Exception ex) { return new HttpStatusCodeResult(HttpStatusCode.ServiceUnavailable, ex.Message); } }
View a Campaign’s details
Looking at a Campaign’s properties is as simple as providing its Id to the MailChimpManager.Campaigns.GetAsync method.
public async Task<ActionResult> Detail() { var model = await Manager.Campaigns.GetAsync("d4688e21b2"); return View(model); }
Here’s the View I am using, which does not show all the properties of a Campaign object; just the ones I think are most relevant.
@model MailChimp.Net.Models.Campaign @{ ViewBag.Title = $"Detail for campaign ID {Model.Id}"; } <h2>Detail for Campaign ID @Model.Id</h2> <dl class="row"> <dt class="col-md-3 text-right">Title</dt> <dd class="col-md-9">@Model.Settings.Title</dd> <dt class="col-md-3 text-right">Content Type</dt> <dd class="col-md-9">@Model.ContentType</dd> <dt class="col-md-3 text-right">Create Time</dt> <dd class="col-md-9">@Model.CreateTime.ToString("s")</dd> <dt class="col-md-3 text-right">Status</dt> <dd class="col-md-9">@Model.Status</dd> <dt class="col-md-3 text-right">Delivery Status</dt> <dd class="col-md-9"> @if (Model.DeliveryStatus.Status != null) { @Model.DeliveryStatus.Status } else { @Html.Raw("NULL") } </dd> <dt class="col-md-3 text-right">Type</dt> <dd class="col-md-9">@Model.Type</dd> </dl>
List all Campaigns
You can generate a list of all Campaigns by creating a CampaignRequest class to filter your results, then calling MailChimpManager.Campaigns.GetAllAsync with that filter as its argument.
In my case, I’m going to get a list of the last 10 saved Campaigns for a specific List.
public async Task<ActionResult> Index() { var options = new CampaignRequest { ListId = "f809a0eba9", Status = CampaignStatus.Save, SortOrder = CampaignSortOrder.DESC, Limit = 10 }; ViewBag.ListId = "f809a0eba9"; try { var model = await Manager.Campaigns.GetAllAsync(options); return View(model); } catch (MailChimpException mce) { return new HttpStatusCodeResult(HttpStatusCode.BadGateway, mce.Message); } catch (Exception ex) { return new HttpStatusCodeResult(HttpStatusCode.ServiceUnavailable, ex.Message); } }
Here’s the relatively simple View:
@model IEnumerable<MailChimp.Net.Models.Campaign> @{ ViewBag.Title = $"Campaigns for list ID {ViewBag.ListId}"; } <h2>Campaigns for List ID @ViewBag.ListId</h2> <table class="table table-striped table-bordered"> <thead> <tr> <th>ID</th> <th>Title</th> <th>Emails Sent</th> <th>View</th> </tr> </thead> <tbody> @foreach (var campaign in Model) { <tr> <td>@campaign.Id</td> <td>@campaign.Settings.Title</td> <td>@campaign.EmailsSent</td> <td><a href="@campaign.ArchiveUrl" target="_viewCampaign">View »</a></td> </tr> } </tbody> </table>
Delete a Campaign
Deleting a Campaign is basically the same as getting its details: Just provide an ID to the MailChimpManager.Campaigns.DeleteAsync method.
public async Task<ActionResult> Delete() { try { await Manager.Campaigns.DeleteAsync("d4688e21b2"); return RedirectToAction("Index"); } catch (MailChimpException mce) { return new HttpStatusCodeResult(HttpStatusCode.BadGateway, mce.Message); } catch (Exception ex) { return new HttpStatusCodeResult(HttpStatusCode.ServiceUnavailable, ex.Message); } }
And that’s it for the series. I hope you enjoyed it.
Github repo for all the code in these demos: https://github.com/dougvdotcom/MailChimpNetDemo

Hi Doug Vanderweide,
Thanks for such a great blog regarding Mail Chimp from basic setup to send campaign. I found all the information looking for and better way to use Mail Chimp from your blog.
I need your help or opinion for following scenario:-
We are developing application for our client using Mail Chimp Version 3.0 by Brandon Seydel .Net wrapper. I attached the screen shot of Mail Chimp .Net wrapper used in application.
My client require additional functionality to send unique or sometime multiple attachment to each subscriber added in list while we send campaign.
Please suggest us appropriate solution.
@Gusharan: Per the TOS, you cannot send transactional email through MailChimp.
As the link explains, transactional email is any message that is specific to a person. Since you intend to send to your customers emails that are specific to them, with attachments, you need a transactional email service.
You can use Mandrill, which is MailChimp’s transactional email service, to this end. There are other transactional email providers out there, however, notably SendGrid.
All tutorials aboul interaction with was great! I really have learnt a lot!
I have an issue/question and I don’t know how to solve it.
In the above code you are using the entire list of recipients:
if I would like to send to filtered recipients, how this could be done? How can I filter based on Interestings and Groups?
Thank you
@Makis,
You would use the SegmentOptions class. For example, to send to saved segment ID 1000:
You can also use matches and conditions for dynamic segments.
Hello,
I am following your example and when I get to the content upload part, I receive this error “Unexpected character encountered while parsing value: <. Path '', line 0, position 0."
Everything I did I as wrote in this example and I am not too sure what's wrong with it …
Thx for any help you could provide
@Alex: The error is self-explanatory: You’re passing in a left-angle bracket (<) where one doesn’t belong.
Since I can’t see your code I can’t help you. If you want to put it up in a pastebin or gist I can take a quick look. But just like you, I do not work for free.
Like I said, it’s pretty much as your example which I used in a part of my application “as is” for starter then once I saw how the full cycle worked i’d do my own code.
So here is the pastebin:
https://pastebin.com/mGnG5fiJ
the code send the error at the line “await mc_mngr.Content.AddOrUpdateAsync(aCampaign.Id, content);”
Nevermind … I got it, pretty stupid error, forgot to get the campaign object back from the first call … so I had no ID which led to the error. The error itself isn’t too expressive actually
Hi, Doug. Very helpful tutorials.
I have a question, how can I get a list of letters (email) received / open for each member in the campaign?
@eugene: It doesn’t appear that the MailChimp.NET.V3 library supports the Campaign Opens endpoint. You can, however, extend MailChimp.NET.V3 to do so. That’s a bit more involved of a task than I care to get into with a comment.
Basically, you will want to build upon the ReportLogic class. You need to add a new model that looks like the response body that comes back from the API endpoint, then wire up a new async method in your derived ReportLogic class that feeds out to that model.
Ideally, once you have done that, you’d issue a pull request on the repo so that others can benefit from your work.
Alternatively, you can call directly to the MailChimp REST API.
@Doug: Sorry Doug, I probably incorrectly formulated the question, I need not just information on sent letters, namely the body of the letter that was sent, with all permutations with merge tags.I could not find this information in the MailChimp API, maybe you can tell how to do it 🙂
@eugenebarnatskiy: There are a couple of options. You can use the Content.GetAsync() method to get the content of a specific campaign by ID. That will return a Content object, which has a property named Html which will show you the HTML markup, including merge tags.
Alternatively, you can use the Campaign.GetAsync() method to retrieve the campaign. That will return a Campaign object with a property of ArchiveUrl, which is a link to the content that was sent.
There’s probably a way to see the content of an email sent to a specific member for a campaign, if that’s what you are after; but I’m too lazy to locate it.
@Doug: Yeap, for my task it is necessary to get the message sent to each participant of the list, unfortunately there is no such functionality in the MailChimp API 🙁
Hi,
Great tutorials!
How do I transfer them to AsP.Net Core?
Doesn’t work in AsP.Net Core?
Thanks,
Poul Erik
@Poul: “doesn’t work” is not particularly useful. What errors do you receive?
Hi Doug,
1)
Error: Manager does not exist in current context!
2)
Error: The type or namespace ‘HttpStatusCodeResult’ could not be found
3)
Error: As 2)
Hope you can help!
Thanks Doug,
Regards,
Poul Erik
@Poul:
Most likely you have failed to import the required namespaces. Alongside all your other using statements, you need to add:
I have:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using MailChimp.Net;
using MailChimp.Net.Core;
using MailChimp.Net.Interfaces;
using MailChimp.Net.Models;
using Microsoft.AspNetCore.Mvc;
I think it’s something about Microsoft.AspNetCore.Mvc;?
@Poul: That’s correct. If you’re building in .NET Core, your assemblies will differ from those used here, which is .NET Framework.
Okay.
Is it possible to fix that?
@Poul: Of course. Use the .NET Framework, or use a response that exists in .NET Core.