I need to embed 5 links in a row with images in a MailMessage using C#. The problem is only the last embedded image displays in the email. The result I need is this:
Here is what displays in the delivered email:
Here is my code:
public void SendMail()
{
MailMessage mail = new MailMessage();
mail.IsBodyHtml = true;
mail.AlternateViews.Add(GetEmbeddedImage(images));
......
}
private AlternateView GetEmbeddedImage(List<string> images)
{
AlternateView alternateView = null;
string body = "";
string link = #"<a href='http://localhost:55148/Support/Management/Index'>";
for (int i = 0; i < images.Count; i++)
{
string filepath = images[i];
LinkedResource res = new LinkedResource(filepath, MediaTypeNames.Image.Jpeg);
res.ContentId = Guid.NewGuid().ToString();
body = body + link + #"<img src='cid:" + res.ContentId + #"'/></a>";
alternateView = AlternateView.CreateAlternateViewFromString(body, null, MediaTypeNames.Text.Html);
alternateView.LinkedResources.Add(res);
}
return alternateView;
}
I figured it out. I don't know why it made a difference, but I collected the LinkedResources into a list and then added them using a foreach:
AlternateView alternateView = null;
string body = "";
string link = #"<a href='http://localhost:55148/Support/Management/Index'>";
List<LinkedResource> resources = new List<LinkedResource>();
for (int i = 0; i < images.Count; i++)
{
string filepath = images[i];
LinkedResource res = new LinkedResource(filepath, MediaTypeNames.Image.Jpeg);
res.ContentId = Guid.NewGuid().ToString();
body = body + link + #"<img src='cid:" + res.ContentId + #"'/></a>";
alternateView = AlternateView.CreateAlternateViewFromString(body, null, MediaTypeNames.Text.Html);
resources.Add(res);
}
foreach(LinkedResource r in resources)
{
alternateView.LinkedResources.Add(r);
}
return alternateView;
Related
I am using Mailkit library to send e-mails. This is the code to do so:
public async Task SendAsync(IdentityMessage message)
{
if (message == null)
return;
LinkedResource inline = new LinkedResource(System.Web.Hosting.HostingEnvironment.MapPath($"~/Images/logo.png"))
{
ContentId = Guid.NewGuid().ToString(),
ContentType = new ContentType("image/png")
{
Name = "logo.png"
}
};
var htmlBody = message.Body.Replace("{CID:LOGO}", String.Format("cid:{0}", inline.ContentId));
AlternateView avHtml = AlternateView.CreateAlternateViewFromString(htmlBody, null, MediaTypeNames.Text.Html);
avHtml.LinkedResources.Add(inline);
using (MailMessage objMailMsg = new MailMessage())
{
objMailMsg.AlternateViews.Add(avHtml);
objMailMsg.Body = htmlBody;
objMailMsg.Subject = message.Subject;
objMailMsg.BodyEncoding = Encoding.UTF8;
Properties.Settings.Default.Reload();
string fromEmail = Properties.Settings.Default.FromMail;
string fromName = Properties.Settings.Default.FromName;
string smtpPassword = Properties.Settings.Default.PwdSmtp;
objMailMsg.From = new MailAddress(fromEmail, fromName);
objMailMsg.To.Add(message.Destination);
objMailMsg.IsBodyHtml = true;
MimeMessage mime = MimeMessage.CreateFromMailMessage(objMailMsg);
HeaderId[] headersToSign = new HeaderId[] { HeaderId.From, HeaderId.Subject, HeaderId.Date };
string domain = "example.cl";
string selector = "default";
DkimSigner signer = new DkimSigner(#"C:\inetpub\dkim.pem", domain, selector)
{
HeaderCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Relaxed,
BodyCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple,
AgentOrUserIdentifier = "#contact.example.cl",
QueryMethod = "dns/txt",
};
mime.Prepare(EncodingConstraint.EightBit);
signer.Sign(mime, headersToSign);
using (SmtpClient smtpClient = new SmtpClient())
{
await Task.Run(() =>
{
try
{
smtpClient.Connect(Properties.Settings.Default.ServidorSmtp, Properties.Settings.Default.PuertoSmtp, Properties.Settings.Default.SSLSmtp);
smtpClient.Authenticate(fromEmail, smtpPassword);
smtpClient.Send(mime);
smtpClient.Disconnect(true);
}
catch (Exception ex)
{
ErrorLog.Save(ex);
//InfoLog.Save(htmlBody);
}
});
}
}
}
Well.. when the e-mail arrives, e-mail client shows it correctly in HTML format. However, an HTML file is attached in the e-mail also.
That file is named, for example, Attached data without title 00391.html. If I open that file in browser, the e-mail body is shown.
I have not found a way to change the name of that attachment.
Does anyone know?
The problem is probably this:
var htmlBody = message.Body.Replace("{CID:LOGO}", String.Format("cid:{0}", inline.ContentId));
AlternateView avHtml = AlternateView.CreateAlternateViewFromString(htmlBody, null, MediaTypeNames.Text.Html);
// ...
objMailMsg.AlternateViews.Add(avHtml);
objMailMsg.Body = htmlBody;
You are setting the HTML body text as 2 different body parts. If you create the avHtml part, you shouldn't also need to set objMailMsg.Body = htmlBody.
When MailKit later converts the System.Net.Mail.MailMessage into a MimeMessage, it probably ends up with 2 duplicate parts, one that gets used as the actual HTML body and one that gets added as an attachment w/o a name (the receiving client likely assigns this part a random name which is what you are seeing).
Alternatively, you could remove the logic that creates a System.Net.Mail.MailMessage completely and just construct a MimeMessage and avoid potential issues in conversion.
var bodyBuilder = new BodyBuilder ();
var logo = bodyBuilder.LinkedResources.Add (System.Web.Hosting.HostingEnvironment.MapPath($"~/Images/logo.png"));
var htmlBody = message.Body.Replace("{CID:LOGO}", String.Format("cid:{0}", logo.ContentId));
bodyBuilder.HtmlBody = htmlBody;
Properties.Settings.Default.Reload();
string fromEmail = Properties.Settings.Default.FromMail;
string fromName = Properties.Settings.Default.FromName;
string smtpPassword = Properties.Settings.Default.PwdSmtp;
var mime = new MimeMessage ();
mime.From.Add (new MailboxAddress (fromName, fromEmail));
mime.To.Add (MailboxAddress.Parse (message.Destination));
mime.Subject = message.Subject;
mime.Body = bodyBuilder.ToMessageBody ();
HeaderId[] headersToSign = new HeaderId[] { HeaderId.From, HeaderId.Subject, HeaderId.Date };
string domain = "example.cl";
string selector = "default";
DkimSigner signer = new DkimSigner(#"C:\inetpub\dkim.pem", domain, selector)
{
HeaderCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Relaxed,
BodyCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple,
AgentOrUserIdentifier = "#contact.example.cl",
QueryMethod = "dns/txt",
};
mime.Prepare(EncodingConstraint.EightBit);
signer.Sign(mime, headersToSign);
I am trying to send an email via Sendgrid using the following code. The email has an image which I am trying to send.
var client = new SendGridClient("MYAPIKEY");
var from = new EmailAddress("from#from.com");
var subject = "test";
var to = new EmailAddress("to#to.com");
var plainTextContent = "";
Image s = CreateBitmapImage("Hi");
ImageConverter converter = new ImageConverter();
var imageBytes = (byte[])converter.ConvertTo(s, typeof(byte[]));
var b64String = Convert.ToBase64String(imageBytes);
var dataUrl = "data:image/jpg;base64," + b64String;
var htmlContent = "<img src='" + dataUrl + "' />";
var msg = MailHelper.CreateSingleEmail(from, to, subject, plainTextContent, htmlContent);
var response = client.SendEmailAsync(msg).Result;
Following is what i see in gmail after sending the image.
I referred to sendgrid blogpost for embedding image via base64. Please suggest if I am doing wrong somewhere.
Do you check if you have it set?
MailMessage msg = new MailMessage();
msg.IsBodyHtml = true;
msg.BodyEncoding = Encoding.GetEncoding("utf-8");
If you set,you trying
var dataUrl = "";
using (System.Drawing.Image s = CreateBitmapImage("Hi"))
{
ImageConverter converter = new ImageConverter();
var imageBytes = (byte[])converter.ConvertTo(s, typeof(byte[]));
var b64String = Convert.ToBase64String(imageBytes);
dataUrl = "data:image/jpg;base64," + b64String;
}
var htmlContent = "<img src=\"" + dataUrl + "\" />";
var msg = new AE.Net.Mail.MailMessage
{
Subject = subject,
Body = bodyhtml,
From = new System.Net.Mail.MailAddress("myemail")
};
foreach (string add in vendorEmailList.Split(','))
{
if (string.IsNullOrEmpty(add))
continue;
msg.To.Add(new System.Net.Mail.MailAddress(add));
}
msg.ReplyTo.Add(msg.From); // Bounces without this!!
msg.ContentType = "text/html";
////attachment code
foreach (string path in attachments)
{
var bytes = File.ReadAllBytes(path);
string mimeType = MimeMapping.GetMimeMapping(path);
AE.Net.Mail.Attachment attachment = new AE.Net.Mail.Attachment(bytes, mimeType, Path.GetFileName(path), true);
msg.Attachments.Add(attachment);
}
////end attachment code
var msgStr = new StringWriter();
msg.Save(msgStr);
Message message = new Message();
message.Raw = Base64UrlEncode(msgStr.ToString());
var result = gmailService.Users.Messages.Send(message, "me").Execute();
This code is working without attachment but with attachment instead of attachment directly byte[] is appearing in inbox.
If i remove msg.ContentType = "text/html" this line then it is working but html not rendering in email, appearing as plain text.
I want to send both HTML body and attachment, Please help.
MailMessage mail = new MailMessage();
mail.Subject = subject;
mail.Body = bodyhtml;
mail.From = new MailAddress("myemail");
mail.IsBodyHtml = true;
foreach (string add in vendorEmailList.Split(','))
{
if (string.IsNullOrEmpty(add))
continue;
mail.To.Add(new MailAddress(add));
}
foreach (string add in userEmailList.Split(','))
{
if (string.IsNullOrEmpty(add))
continue;
mail.CC.Add(new MailAddress(add));
}
foreach (string path in attachments)
{
//var bytes = File.ReadAllBytes(path);
//string mimeType = MimeMapping.GetMimeMapping(path);
Attachment attachment = new Attachment(path);//bytes, mimeType, Path.GetFileName(path), true);
mail.Attachments.Add(attachment);
}
MimeKit.MimeMessage mimeMessage = MimeMessage.CreateFromMailMessage(mail);
Message message = new Message();
message.Raw = Base64UrlEncode(mimeMessage.ToString());
var result = gmailService.Users.Messages.Send(message, "me").Execute();
I found solution after lot of efforts. Instead of AE.Net.Mail.MailMessage used System.Net.Mail.MailMessage and MimeKit to convert it to raw string. And now html body with attachment is working fine.
try adding IsBodyHtml = true
new AE.Net.Mail.MailMessage
{
Subject = subject,
Body = bodyhtml,
From = new System.Net.Mail.MailAddress("myemail")
IsBodyHtml = true
};
I have written below code to embed image in the mail which is being sent from my c# code. But when i check the mail, i get image like an attachment and not as an inline image. (Gmail)
AlternateView htmlBodyView = null;
string htmlBody = "<html><body><h1></h1><br><img src=\"cid:SampleImage\"></body></html>";
AlternateView plainTextView = AlternateView.CreateAlternateViewFromString(htmlBody, null, "text/html");
ImageConverter ic = new ImageConverter();
Byte[] ba = (Byte[])ic.ConvertTo(bitmap_obj, typeof(Byte[]));
using (MemoryStream logo = new MemoryStream(ba))
{
LinkedResource sampleImage = new LinkedResource(logo, "image/jpeg");
sampleImage.ContentId = "sampleImage";
htmlBodyView.LinkedResources.Add(sampleImage);
p.SendEmail(htmlBodyView);
}
For reference, a full working simplified example:
public void SendMail()
{
LinkedResource logo = new LinkedResource(
"images\\image005.png", //Path of file
"image/png"); //Mime type: Important!
logo.ContentId = "logo"; //ID for reference
//Actual HTML content of the body in an 'AlternateView' object.
AlternateView vw = AlternateView.CreateAlternateViewFromString(
"Hello, this is <b>HTML</b> mail with embedded image: <img src=\"cid:logo\" />",
null,
MediaTypeNames.Text.Html); //Mime type: again important!
vw.LinkedResources.Add(logo);
var msg = new MailMessage() { IsBodyHtml = true };
msg.AlternateViews.Add(vw);
msg.From = new MailAddress("sender#domain.com");
msg.To.Add(new MailAddress("reciever#domain.com"));
msg.Subject = "HTML Mail!";
using (var client = new SmtpClient("localhost", 25))
client.Send(msg);
}
How can i add an image to an email message sent from a web server in C#
this is the code i am using:
string emailType = "NewMember";
string sMessage = GetData.emailText(emailType);
string sEmail = GetData.userEmails(userName);
string sSubject = GetData.emailSubject(emailType);
SmtpClient smtpClient = new SmtpClient();
string htmlBody = "<html><body>Dear " + userName + sMessage + "<br/><br/><img src=\"cid:filename\"></body></html>";
AlternateView avHtml = AlternateView.CreateAlternateViewFromString
(htmlBody, null, MediaTypeNames.Text.Html);
LinkedResource inline = new LinkedResource("~/Resources/images/logo.jpg", MediaTypeNames.Image.Jpeg);
inline.ContentId = Guid.NewGuid().ToString();
avHtml.LinkedResources.Add(inline);
MailMessage mail = new MailMessage();
mail.AlternateViews.Add(avHtml);
Attachment att = new Attachment("~/Resources/images/logo.jpg");
att.ContentDisposition.Inline = true;
MailAddress sFrom = new MailAddress("info#website.com");
MailAddress sTo = new MailAddress(sEmail);
mail.From = sFrom;
mail.To.Add(sTo);
mail.Subject = sSubject;
mail.Body = String.Format(
htmlBody +
#"<img src=""cid:{0}"" />", inline.ContentId);
mail.IsBodyHtml = true;
mail.Attachments.Add(att);
smtpClient.Send(mail);
`
this is the error message i am getting:
Could not find a part of the path 'C:\Windows\SysWOW64\inetsrv\~\Resources\images\logo.jpg
Try -
Attachment att = new Attachment(Server.MapPath("~/Resources/images/logo.jpg"));
LinkedResource inline = new LinkedResource(Server.MapPath("~/Resources/images/logo.jpg"), MediaTypeNames.Image.Jpeg);
Instead of -
Attachment att = new Attachment("~/Resources/images/logo.jpg");
LinkedResource inline = new LinkedResource("~/Resources/images/logo.jpg", MediaTypeNames.Image.Jpeg);
Because you need the path of the resource that is inside website folder. So you have to map path with Server.MapPath. More details here -
Server.MapPath Method