I am using Sendgrid to send emails with templates that contain multiple variables.
Everything works well when I have only one recipient for an email.
When I have multiple recipients either in To or one in To and one in Cc, the first email is ok but the following have empty strings in the substition tags.
Below is my code :
private bool SendEmail(MailAddress from, string[] to, string template, Dictionary<string, string> keyToReplace, string[] cc = null)
{
var message = new SendGridMessage();
message.From = from;
message.AddTo(to);
if (cc != null && cc.Any())
{
foreach (var ccAddress in cc)
{
message.AddCc(ccAddress);
}
}
message.Subject = " ";
message.Text = string.Empty;
message.Html = "<p></p>";
message.EnableTemplate("<%body%>");
message.EnableTemplateEngine(templateIds[template]);
foreach (var keyValue in keyToReplace)
{
var key = keyValue.Key;
if (!key.StartsWith("#"))
{
key = string.Format("#{0}#", key);
}
var value = keyValue.Value;
if (string.IsNullOrEmpty(keyValue.Value))
{
value = " ";
}
message.AddSubstitution(key, new List<string> { value });
}
var transportWeb = transportFactory(credentials);
transportWeb.Deliver(message);
logger.Info("Mail sent to : " + string.Join(", ", to));
return true;
}
I enventually updated the Sendgrid nuget package from version 5.0.0 to version 9.5.0 and it fixed the issue.
Related
I'm trying to remove or exclude a couple specific e-mail addresses from the CC e-mail address list. How should I do this? Here is the function:
private void SendEmail(string emailTo, string subject, string body)
{
using (SmtpClient client = new SmtpClient(System.Configuration.ConfigurationManager.AppSettings["SmtpServerAddress"]))
{
MailMessage email = new MailMessage();
email.From = new MailAddress(GetUserEmail());
string emailCc = ConfigurationManager.AppSettings["EmailCc"];
foreach (var item in emailTo.Split(';'))
{
email.To.Add(new MailAddress(item.Trim()));
}
foreach (var item in emailCc.Split(';'))
{
email.CC.Add(new MailAddress(item.Trim()));
}
email.Subject = subject;
email.IsBodyHtml = true;
email.Body = body;
return;
}
}
You put the emails you don't want into an array:
var badEmails = new [] { "a#a.aa", "b#b.bb" }
Then you use LINQ to remove them from the split:
var ccList = emailCc.Split(';').Where(cc => !badEmails.Any(b => cc.IndexOf(b, System.StringComparison.InvariantCultureIgnoreCase) > -1));
Then you add those in ccList to your email
You can try with this if you know email:
foreach (var item in emailCc.Split(';'))
{
if (!new string[] { "bad#gmail.com", "uncle#sam.com", "stack#overflow.com"}.Contains(email))
{
email.CC.Add(new MailAddress(item.Trim()));
}
}
instead of if statement you can use regular expression if you want to exclude some email with specific pattern.
Here is my Code snippet to send email using postmark
public async Task<bool> SendEmail(CustomMailMessage mailMessage)
{
HeaderCollection headers = new HeaderCollection();
if (mailMessage.Headers != null)
{
var items = mailMessage.Headers.AllKeys.SelectMany(mailMessage.Headers.GetValues, (k, v) => new { key = k, value = v });
foreach (var item in items)
{
headers.Add(item.key, item.value);
}
}
var message = new PostmarkDotNet.PostmarkMessage()
{
To = mailMessage.To,
Cc = mailMessage.Cc,
Bcc = mailMessage.Bcc,
From = mailMessage.FromName + "<" + mailMessage.From + ">",
TrackOpens = true,
Subject = mailMessage.Subject,
TextBody = mailMessage.Body,
HtmlBody = mailMessage.HtmlBody,
Headers = headers,
};
if (mailMessage.AttachmentsPath != null)
{
foreach (string file in mailMessage.AttachmentsPath)
{
var imageContent = File.ReadAllBytes(file);
message.AddAttachment(imageContent, Path.GetFileName(file), MimeMapping.GetMimeMapping(file), null);
}
}
var client = new PostmarkClient(ConfigurationSettings.AppSettings["postmarkServerToken"].ToString(), "https://api.postmarkapp.com", 30);
var sendResult = await client.SendMessageAsync(message);
if (sendResult.Status== PostmarkStatus.Success)
{
return true;
}
else
{
return false;
}
}
When I try to send email "var sendResult = await client.SendMessageAsync(message);" didn't get any response when hitting this line, and when send mail again got message "The transaction has aborted."
Please Help
I'm using Sendgrid and try to sending these emails with C# language.
So, what i'm doing is configure the SMTP and API Keys in my apps, and boom, there goes the emails were sent.
The question is, How do I insert the Unsubscribe Preferences group in my X-SMTPAPI header?
FYI, unsubscribe preferences is where you can choose which group you want to unsubscribe instead of global unsubscribe.
I already checked these links:
https://sendgrid.com/docs/API_Reference/Web_API_v3/Suppression_Management/groups.html
https://sendgrid.com/docs/API_Reference/Web_API_v3/How_To_Use_The_Web_API_v3/requests.html
https://sendgrid.com/docs/API_Reference/SMTP_API/suppressions.html
I also checked the library C# on their github.
But none of these is made me clear.
I'm completely blind with JSON, GET, REQUEST, RESPONSE and such.
this is my C# code
public void Main()
{
string sSubject = Dts.Variables["vSubject"].Value.ToString();
string sBody = Dts.Variables["vBodyMessage"].Value.ToString();
int iPriority = 2;
if (SendMail(sSubject, sBody, iPriority))
{
Dts.TaskResult = (int)ScriptResults.Success;
}
else
{
//Fails the Task
Dts.TaskResult = (int)ScriptResults.Failure;
}
}
//THIS IS THE HEADER X-SMTPAPI, I DUNNO HOW TO USE IT :(
//I WANNA ADD MY GROUPS HERE
private static string XsmtpapiHeaderAsJson()
{
var header = new Header();
header.SetAsmGroupId(777);
//var uniqueArgs = new string[] { "Small", "Medium", "Large" };
//{
// "asm_groups_to_display": [1, 2, 3]
//};
//header.AddUniqueArgs({ "asm_groups_to_display": ['1', '2', '3']});
//var subs = new List<String> { "私はラーメンが大好き" };
//header.AddSubstitution("%tag%", subs);
//dynamic stuff = json
return header.JsonString();
}
public bool SendMail(string sSubject, string sMessage, int iPriority)
{
string xmstpapiJson = XsmtpapiHeaderAsJson();
try
{
string sEmailServer = Dts.Variables["sServer"].Value.ToString();
string sEmailPort = Dts.Variables["sPort"].Value.ToString();
string sEmailUser = Dts.Variables["sUser"].Value.ToString();
string sEmailPassword = Dts.Variables["sPassword"].Value.ToString();
string sEmailSendTo = Dts.Variables["sSendTo"].Value.ToString();
string sEmailSendToName = Dts.Variables["sSendToName"].Value.ToString();
//string sEmailSendCC = Dts.Variables["sSendCC"].Value.ToString();
string sEmailSendFrom = Dts.Variables["sFrom"].Value.ToString();
string sEmailSendFromName = Dts.Variables["sFromName"].Value.ToString();
SmtpClient smtpClient = new SmtpClient();
MailMessage message = new MailMessage();
MailAddress fromAddress = new MailAddress(sEmailSendFrom, sEmailSendFromName);
//You can have multiple emails separated by ;
string[] sEmailTo = Regex.Split(sEmailSendTo, ";");
//string[] sEmailCC = Regex.Split(sEmailSendCC, ";");
int sEmailServerSMTP = int.Parse(sEmailPort);
smtpClient.Host = sEmailServer;
smtpClient.Port = sEmailServerSMTP;
System.Net.NetworkCredential myCredentials =
new System.Net.NetworkCredential(sEmailUser, sEmailPassword);
smtpClient.Credentials = myCredentials;
message.From = fromAddress;
//MailAddress toAddress = new MailAddress(sEmailSendTo, sEmailSendToName);
//message.To.Add(toAddress);
if (sEmailTo != null)
{
for (int i = 0; i < sEmailTo.Length; ++i)
{
if (sEmailTo[i] != null && sEmailTo[i] != "")
{
MailAddress toAddress = new MailAddress(sEmailTo[i], sEmailSendToName);
message.To.Add(toAddress);
}
}
}
switch (iPriority)
{
case 1:
message.Priority = MailPriority.High;
break;
case 3:
message.Priority = MailPriority.Low;
break;
default:
message.Priority = MailPriority.Normal;
break;
}
//message.Headers.Add("X-SMTPAPI", xmstpapiJson);
//smtpClient.SendCompleted += SendCompletedCallback;
//const string state = "test1";
message.Subject = sSubject;
message.IsBodyHtml = true;
message.Body = sMessage;
//smtpClient.SendAsync(message, state);
smtpClient.Send(message);
return true;
}
catch (Exception ex)
{
return false;
}
}
I see what you mean, the smtpapi-csharp project simply doesn't have that concept implemented.. but it's a trivial matter. (the value of this utility project is questionable to begin with).
Really the only piece of importance here is commented out.
//message.Headers.Add("X-SMTPAPI", xmstpapiJson);
Should be,
message.Headers.Add("X-SMTPAPI", #"{ ""asm_group_id"" : 777, ""asm_groups_to_display"" : [777] }");
Essentially, you're just assigning json to this header. The Documentation provides this sample
{
"asm_groups_to_display": [1, 2, 3]
}
[1, 2, 3] is an array of integers, which correlates to GroupIds.
Alternatively,
fork the git and add the following to Header.cs
/// <summary>
/// This sets which groups to display on the Manage Preferences page of an email. You can find further documentation about ASM here:
/// https://sendgrid.com/docs/API_Reference/SMTP_API/suppressions.html
/// </summary>
/// <param name="ids">ASM groups to display applied to the message</param>
public void SetAsmGroupsToDisplay(params int[] ids)
{
_settings.AddArray(new List<string> {"asm_groups_to_display"}, ids);
}
Build and update your csproj reference to use your forked project.
then, call SetAsmGroupsToDisplay like so,
private static string XsmtpapiHeaderAsJson()
{
var header = new Header();
header.SetAsmGroupId(777);
header.SetAsmGroupsToDisplay(777); // SetAsmGroupsToDisplay(new int[] {777}) works too
return header.JsonString();
}
and, of course, use the method:
message.Headers.Add("X-SMTPAPI", XsmtpapiHeaderAsJson());
... don't forgot to add a Pull Request when you get it working.
I have a system that sends emails with inline pictures. The problem is how Outlook 2013 displays the attachments. Can I update my code in a way that tells outlook not to display the paperclip icon seen here?
The idea is that I only want to display this icon when full sized pictures are attached. Not inline attachments.
Here's the code that generates the email. Create a basic console app, specify your To / mailserver / picture path, and run.
static void Main(string[] args)
{
Console.WriteLine("Prepping email message....");
var subject = "Test Subject With Inline";
var message = "<p>This is a test message.</p><br/><br/><p>[CompanyLogo]</p>";
var to = new List<string>();
to.Add("My.Name#company.com");
Console.WriteLine("Sending email message....");
if (SendMessageToFrom(subject, message, to, new List<string>()))
{
Console.WriteLine("Email sent! Check your inbox.");
}
else
{
Console.WriteLine("Error sending email!");
}
}
public static bool SendMessageToFrom(String subject, String message, List<String> to, List<String> cc)
{
try
{
// Construct the email
var sendMessage = new MailMessage()
{
IsBodyHtml = true,
From = new MailAddress("noreply#company.com"),
Subject = subject,
Body = message
};
if (sendMessage.Body.Contains("[CompanyLogo]"))
{
sendMessage.AlternateViews.Add(EmbedLogo(sendMessage.Body));
}
// Add the list of recipients
foreach (var recipient in to)
{
sendMessage.To.Add(recipient);
}
foreach (var recipient in cc)
{
sendMessage.CC.Add(recipient);
}
//Specify the SMTP server
var smtpServerName = "mailserver.company.com";
var mailClient = new SmtpClient(smtpServerName);
mailClient.Send(sendMessage);
return true;
}
catch
{
throw;
}
}
private static AlternateView EmbedLogo(string html)
{
var inline = new LinkedResource("img\\company-logo.jpg");
inline.ContentId = Guid.NewGuid().ToString();
html = html.Replace("[CompanyLogo]", string.Format(#"<img src='cid:{0}'/>", inline.ContentId));
var result = AlternateView.CreateAlternateViewFromString(html, null, System.Net.Mime.MediaTypeNames.Text.Html);
result.LinkedResources.Add(inline);
return result;
}
Update: Here's the code that did the trick:
private static MailMessage EmbedLogo(MailMessage mail)
{
var inline = new Attachment("img\\company-logo.jpg");
inline.ContentId = Guid.NewGuid().ToString();
inline.ContentDisposition.Inline = true;
inline.ContentDisposition.DispositionType = DispositionTypeNames.Inline;
mail.Body = mail.Body.Replace("[CompanyLogo]", string.Format(#"<img src='cid:{0}'/>", inline.ContentId));
mail.Attachments.Add(inline);
return mail;
}
And I also updated the main method to this:
if (sendMessage.Body.Contains("[CompanyLogo]"))
{
sendMessage = EmbedLogo(sendMessage);
}
Make sure your attachments have the Content-ID MIME header and the message's HTML body refers to them using the cid attribute : <img src="cid:xyz"> (where xyz is the value of the Content-ID MIME header).
I'm attempting to get the email address typed into the To field of a compose mail window.
I try to get the Address property of a Recipient, which according to VS, should give me the email.
I am instead receiving a string that looks like this:
"/c=US/a=att/p=Microsoft/o=Finance/ou=Purchasing/s=Furthur/g=Joe"
How can I get the email address in the recipient field?
My code so far:
List <string> emails = new List<string>();
if (thisMailItem.Recipients.Count > 0)
{
foreach (Recipient rec in thisMailItem.Recipients)
{
emails.Add(rec.Address);
}
}
return emails;
Can you try this ?
emails.Add(rec.AddressEntry.Address);
Reference link
EDIT:
I don't have the right environment to test so I'm just guessing all this, but how about
string email1Address = rec.AddressEntry.GetContact().Email1Address;
or .Email2Adress or .Email3Address
Also there is,
rec.AddressEntry.GetExchangeUser().Address
that you might want to try.
Try this
private string GetSMTPAddressForRecipients(Recipient recip)
{
const string PR_SMTP_ADDRESS =
"http://schemas.microsoft.com/mapi/proptag/0x39FE001E";
PropertyAccessor pa = recip.PropertyAccessor;
string smtpAddress = pa.GetProperty(PR_SMTP_ADDRESS).ToString();
return smtpAddress;
}
This is available on MSDN here
I have used the same way to get email addresses in my application and its working.
the AddressEntry also has an SMTPAddress property that exposes the primary smtp adress of the user.
I don't know if this helps or how accurate
it is, a sample
private string GetSmtp(Outlook.MailItem item)
{
try
{
if (item == null || item.Recipients == null || item.Recipients[1] == null) return "";
var outlook = new Outlook.Application();
var session = outlook.GetNamespace("MAPI");
session.Logon("", "", false, false);
var entryId = item.Recipients[1].EntryID;
string address = session.GetAddressEntryFromID(entryId).GetExchangeUser().PrimarySmtpAddress;
if (string.IsNullOrEmpty(address))
{
var rec = item.Recipients[1];
var contact = rec.AddressEntry.GetExchangeUser();
if (contact != null)
address = contact.PrimarySmtpAddress;
}
if (string.IsNullOrEmpty(address))
{
var rec = item.Recipients[1];
var contact = rec.AddressEntry.GetContact();
if (contact != null)
address = contact.Email1Address;
}
return address;
}
finally
{
}
}