SendGrid - Image not showing up in HTML email - c#

I am using the SendGrid v3 API and C# library (v7) to send an email.
In my email I have a header which is a png. The header is embedded like this:
<img src="cid:emailheader"/>
In the C# code I send the image as an attachment with with the same ContentId
var mail = new Mail(from, subject, to, content);
var headerPath = HttpContext.Current.Server.MapPath("~/Resources/email-header.png");
var attachment = new SendGrid.Helpers.Mail.Attachment();
attachment.ContentId = "emailheader";
attachment.Content = Convert.ToBase64String(File.ReadAllBytes(headerPath));
attachment.Type = "image/png";
attachment.Filename = "email-header.png";
mail.AddAttachment(attachment);
var send = sg.client.mail.send.post(requestBody: mail.Get());
Yet when I open the email it says the source is not found, even though the image is correctly displayed in the attachment

I'm not the expert for Sendgrid, but I found on there blog post
that this suggest to do inline encoding in your html directly. this way you don't need to add an attachment. (I'm use this quite a lot)
<img alt="My Image" src="data:image/jpeg;base64,/9j/4S/+RXhpZgAATU0AKgA...more encoding" />
Maybe this is a work around for you.
As an second alternative:
for sending out emails with pictures I'm using
System.Net.Mail
here I do add an AlternateView with a linked resource.
AlternateView htmlView = AlternateView.CreateAlternateViewFromString(html, null, "text/html");
LinkedResource imageResource = new LinkedResource(Imagepath + "Monitoring.png", "image/png")
{
ContentId = "1",
TransferEncoding = System.Net.Mime.TransferEncoding.Base64
};
htmlView.LinkedResources.Add(imageResource);
message.AlternateViews.Add(htmlView);
the syntax in html is the same as you use
<img src="cid:1">
I hope this help.
Butti

node
//imageData= "data:image/png;base64,ine793nfdsf......."
imageb64 = imageData.replace('data:image/png;base64,' , '');
//remove data:image/png;base64,
const msg = {
to: 'example#gmail.com',
from: 'test#gmail.com',
subject: "image attached",
html :'<img src="cid:myimagecid"/>',
attachments: [
{
filename: "imageattachment.png",
content: imageb64,
content_id: "myimagecid",
}
]
};
sgMail.send(msg);

Related

How Can I add a PDF file on my local machine as an attachment to Teams chat using Graph API, so that everyone in the chat can access the file

I tried the following code and it didn't worked out.
Byte[] bytes = System.IO.File.ReadAllBytes(filePath);
String file = Convert.ToBase64String(bytes);
chatMessage = new ChatMessage
{
Body = new ItemBody
{
ContentType = BodyType.Html,
Content ="this is test message, <attachment id=" + "someguid ID" + "></attachment>"
},
Attachments = new List<ChatMessageAttachment>()
{
new ChatMessageAttachment
{
Id = "someguid ID",
ContentType = "application/pdf",
Name = Path.GetFileName(x),
Content = file
}
}
};
await graphClient.Teams[cbTeam.SelectedValue.ToString()].Channels[cbChannel.SelectedValue.ToString()].Messages
.Request()
.AddAsync(chatMessage);
The error I am getting from graph is unable to process the content
From the chatMessage resource type documentation, attachments property is currently read-only and sending attachments is not supported - which would explain the error above. Kindly consider filing a feature request so this can be looked into.
Let me know if this helps.

Attaching to sendgrid api not working when using sendgrid mail helper

I have looked through the questions i can find on here about attaching a file to a sendgrid email but none seem to have the issue I am.
My question is is this. How do you send an email with an attachment in sendgrid using the api?
dynamic sg = new SendGridAPIClient(apiKey);
var from = new SendGrid.Helpers.Mail.Email("jkennedy#domain.com");
var subject = "Hello World from the SendGrid C# Library!";
var to = new SendGrid.Helpers.Mail.Email(toAddress);
var content = new Content("multipart/form-data", "Textual content");
var attachment = new Attachment {Filename = attachmentPath };
var mail = new Mail(from, subject, to, content);
var ret = mail.Get();
mail.AddAttachment(attachment);
dynamic response = await sg.client.mail.send.post(requestBody: ret);
If i put the mail.attachment after the get the mail sends but there is no attachment. If i put the addattachment line before the get i get a "bad request" message.
I have yet to find an example of exactly how to do this.
Also, the path to the file is c:\tblaccudatacounts.csv
After struggling with this for a couple hours, I found an answer using sendgrid's V3 API. Here's what I learned.
In your example, you call var ret = mail.Get(); before adding the attachment. Since mail.Get() is essentially serializing the mail object into the Json format SendGrid is expecting, adding the attachment after the mail.Get() call will not actually add it to the mail object.
The other thing you should know is that the API doesn't have a way of simply taking the file path as an input (At least that I can find, I hope someone can correct me). You need to manually set at least the content (as a base 64 string) and filename. You can find more information here.
Here is my working solution:
string apiKey = "your API Key";
dynamic sg = new SendGridAPIClient(apiKey);
Email from = new Email("your#domain.com");
string subject = "Hello World from the SendGrid CSharp Library!";
Email to = new Email("destination#there.com");
Content body = new Content("text/plain", "Hello, Email!");
Mail mail = new Mail(from, subject, to, body);
byte[] bytes = File.ReadAllBytes("C:/dev/datafiles/testData.txt");
string fileContentsAsBase64 = Convert.ToBase64String(bytes);
var attachment = new Attachment
{
Filename = "YourFile.txt",
Type = "txt/plain",
Content = fileContentsAsBase64
};
mail.AddAttachment(attachment);
dynamic response = await sg.client.mail.send.post(requestBody: mail.Get());
I figure it out. I was using a helper written by a third party. I went with what with SendGrid actually suggested. See code below that is now working.
var myMessage = new SendGridMessage {From = new MailAddress("info#email.com")};
myMessage.AddTo("Jeff Kennedy <info#info.com>");
myMessage.Subject = "test email";
myMessage.Html = "<p>See Attachedment for Lead</p>";
myMessage.Text = "Hello World plain text!";
myMessage.AddAttachment("C:\\tblaccudatacounts.csv");
var apiKey = "apikey given by sendgrid";
var transportWeb = new Web(apiKey);
await transportWeb.DeliverAsync(myMessage);

Attachment without filename

When using the System.Net.Mail namespace to send a e-mail with attachment to any Yahoo account the attachment is downloaded with 'untitled' name instead the file name.
In the Yahoo Mail interface the attachment looks with the correct name but when you download it the download name goes to 'untitled' for all attachments. The same e-mail message works fine with Gmail, Outlook.com, Windows Live Mail and other clients.
Looking the raw message it constains a content-type with name but without filename attribute. The Yahoo works fine if the filename attribute is set but C# library don't use this.
That's the header generated by C# for attachments:
Content-Type: application/octet-stream; name=test.pdf
That's the header that works with Yahoo:
Content-Type: application/octet-stream; name=file2; filename=test.pdf
Anyone get this problem so far? Is there a work arround for C# default mail sending?
using (var message = new MailMessage("from#domain", "to#yahoo.com.br", "Test with attachment", "Test with attachment"))
{
var attachment = new Attachment(#"c:\temp\test.pdf"); // Same result using stream instead path to file.
attachment.Name = "test.pdf"; // Same result without this line.
message.Attachments.Add(attachment);
using (var smtp = new SmtpClient("smtp.domain", 587))
{
smtp.Credentials = new NetworkCredential("from#domain", "password");
smtp.Send(message);
}
}
I found a solution:
attachment.ContentDisposition.FileName = "test.pdf";
This add the missing filename attribute in the raw e-mail message and solve the Yahoo limitation.
Have you tried explicitly specifying the content type?
var attachment = new Attachment(... , MediaTypeNames.Application.Octet);

How to send a iCal invite with Mailgun Rest API (C#)

I am attempting to add a calendar invite in iCal format to an email sent via the MailGun API. This is what i have so far:
var request = new RestRequest();
request.AddParameter("domain", this.domain, ParameterType.UrlSegment);
request.Resource = "{domain}/messages";
request.AddParameter("from", contactDetails.SenderAddress);
request.AddParameter("to", contactDetails.RecipientAddress);
request.AddParameter("subject", message.Subject);
request.AddParameter("text", message.TextBody);
request.AddParameter("html", message.HtmlBody);
if (!string.IsNullOrWhiteSpace(message.IcalAttachment))
{
request.AddFileBytes("attachment",
Encoding.UTF8.GetBytes(message.IcalAttachment),
"invite.ics",
"text/calendar");
}
request.Method = Method.POST;
return request;
This results in the calendar being included in the email as an attachment, not an alternative view of the email. The attachment works fine in gmail however in Outlook it appears as an attachment file that you must first click on, then agree to adding the calendar to the Outlook calendar. Is there another way to use the REST api so that the calendar invites are sent correctly, as alternative email views?
To be clear, this is how I would send a calendar invite using .Net SmtpClient:
var contentType = new ContentType("text/calendar");
if (contentType.Parameters != null)
{
contentType.Parameters.Add("method", "REQUEST");
contentType.CharSet = "UTF-8";
}
// this is the same way you add a html view to the message
request.AlternateViews.Add(
AlternateView.CreateAlternateViewFromString(
message.IcalAttachment,
contentType));
Special thanks to Mailgun support for pointing me in the right direction. The relevant part or their response was:
You can use the /message.mime endpoint to construct the MIME for the calendar invite:
https://documentation.mailgun.com/api-sending.html#sending
Creating a mime message isnt as easy as simply using their /message endpoint but there are several .net libraries available to do this. I used MimeKit in this example.
var request = new RestRequest();
request.AddParameter("domain", this.domain, ParameterType.UrlSegment);
request.Resource = "{domain}/messages.mime";
request.AddParameter("to", contactDetails.RecipientAddress);
request.AddFile(
"message",
Encoding.UTF8.GetBytes(BuildMimeContent(message)),
"message.mime");
request.Method = Method.POST;
return request;
The mime content that I want to create will contain a multipart/mixed body, which will in turn contain a multipart/alternative as well as every attachment. The calendar invite will actually be attached twice, as a alternative view and as an attachment. This is to aid in compatibilitiy across different email clients.
The implementation of BuildMimeContent(message) looks like the following:
// create the alternative views
var textBody = new TextPart("plain") { Text = message.TextBody };
var htmlBody = new TextPart("html") { Text = message.HtmlBody };
// add views to the multipart/alternative
var alternative = new Multipart("alternative");
alternative.Add(textBody);
alternative.Add(htmlBody);
if (!string.IsNullOrWhiteSpace(message.CalendarInvite))
{
// also add the calendar as an alternative view
// encoded as base64, but 7bit will also work
var calendarBody = new TextPart("calendar")
{
Text = message.CalendarInvite,
ContentTransferEncoding = ContentEncoding.Base64
};
// most clients wont recognise the alternative view without the
// method=REQUEST header
calendarBody.ContentType.Parameters.Add("method", "REQUEST");
alternative.Add(calendarBody);
}
// create the multipart/mixed that will contain the multipart/alternative
// and all attachments
var multiPart = new Multipart("mixed") { alternative };
if (!string.IsNullOrWhiteSpace(message.CalendarInvite))
{
// add the calendar as an attachment
var calAttachment = new MimePart("application", "ics")
{
ContentDisposition = new ContentDisposition(ContentDisposition.Attachment),
ContentTransferEncoding = ContentEncoding.Base64,
FileName = "invite.ics",
ContentObject = new ContentObject(GenerateStreamFromString(message.CalendarInvite))
};
multiPart.Add(calAttachment);
}
// TODO: Add any other attachements to 'multipart' here.
// build final mime message
var mimeMessage = new MimeMessage();
mimeMessage.From.Add(GetMimeAddress(message.MessageInfo.SenderName, message.MessageInfo.SenderAddress));
mimeMessage.To.Add(GetMimeAddress(message.MessageInfo.RecipientName, message.MessageInfo.RecipientAddress));
mimeMessage.Subject = message.Subject;
mimeMessage.Body = multiPart;
// parse and return mime message
return mimeMessage.ToString();
Warning for people testing with Office 365
Office365 is extremely picky when it comes to validating calendar invites. In order to not get a message like the one below, you will need to ensure that the vCal's organizer email address matches the email's from address. This is not possible if you are using mailgun's sandbox test environment.

Display email as html when client support it otherwise display as plain/text

I want to display email as html if client dont support for html it shud show mail as text/plain. I have written code but not sure can anybody check it how to check for multicontent and multi mimetype here.
mailMessage.IsBodyHtml = true;
mailMessage.From = new MailAddress(from);
foreach (string adress in to)
{
mailMessage.To.Add(adress);
}
string path = string.Empty;
var htmlView = AlternateView.CreateAlternateViewFromString(mailMessage.Body, null, "text/html");
ContentType mimeType = new System.Net.Mime.ContentType("text/html");
// Add the alternate body to the message.
AlternateView alternate = AlternateView.CreateAlternateViewFromString(mailMessage.Body, mimeType);
mailMessage.AlternateViews.Add(alternate);

Categories