I'm trying to send an e-mail with embedded images. Here's what I'm doing...
I have a tinymce text editor where a user can select an image with accompanying text. The e-mail is sent successfully (using CDOSYS - email provider is zohomail) except none of the images are displayed in the e-mail.
Anyone able to tell me what I need to do to display images in an e-mail?
The key function I'm using to convert the image tags to a linked resources is below (uses the agility pack - Install-Package HtmlAgilityPack -Version 1.6.5):
public string ConvertToHtmlDocument(string originalText)
{
HtmlDocument document = new HtmlDocument();
document.LoadHtml(originalText);
document.DocumentNode.Descendants("img").ToList();
foreach(var d in document.DocumentNode.Descendants("img").ToList())
{
string base64String = "";
string currentSrcValue = d.GetAttributeValue("src", null);
string mimeType = MimeMapping.GetMimeMapping(Server.MapPath(currentSrcValue));
using (Image image = Image.FromFile(Server.MapPath(currentSrcValue)))
{
using (MemoryStream m = new MemoryStream())
{
image.Save(m, image.RawFormat);
byte[] imageBytes = m.ToArray();
// Convert byte[] to Base64 String
base64String = Convert.ToBase64String(imageBytes);
}
}
//currentSrcValue = currentSrcValue.Split(',')[1];//Base64 part of string
byte[] imageData = Convert.FromBase64String(base64String);
string contentId = Guid.NewGuid().ToString();
LinkedResource inline = new LinkedResource(new MemoryStream(imageData), mimeType);
inline.ContentId = contentId;
inline.TransferEncoding = TransferEncoding.Base64;
d.SetAttributeValue("src", "cid:" + inline.ContentId);
}
return document.DocumentNode.OuterHtml;
}
[
[
Related
the current code is working but the converted base64string output is attached to the api , but am having 404 error because the request url is too long. so i just need modification , to shorten the converted base64string. or any different approach.
var file = await CrossMedia.Current.PickPhotoAsync(new PickMediaOptions { PhotoSize = PhotoSize.Small });
byte[] imageArray = null;
if (file != null)
{
using (HttpClient client = new HttpClient())
using (MemoryStream ms = new MemoryStream())
{
var stream = file.GetStream();
stream.CopyTo(ms);
imageArray = ms.ToArray();
var base64String = Convert.ToBase64String(imageArray);
I have an .NET Core console application which does some update stuff to my CouchDB.
Now I have to add multiple attachments (in this case images) to my doc.
Here (https://docs.couchdb.org/en/stable/api/document/common.html#attachments) in point 1.4.1.1.4 they describe the way, but I get a Bad Request, I think my json is not perfect.
So I have a list of images that I convert and then send to DB, here is my code:
List<ImageFromApi> imagesFromApi = new List<ImageFromApi>();
string base64String;
foreach (var image in Images)
{
using (image)
{
using (MemoryStream m = new MemoryStream())
{
image.Save(m, image.RawFormat);
byte[] imageBytes = m.ToArray();
// Convert byte[] to Base64 String
base64String = Convert.ToBase64String(imageBytes);
}
}
ImageFromApi Imagebuffer = new ImageFromApi() {
content_type = "image/*",
data = base64String
};
imagesFromApi.Add(Imagebuffer);
DocAttachments bufferData = new DocAttachments() {imagesFromApi = imagesFromApi };
newImages._attachments = bufferData;
}
string imagesJson = JsonConvert.SerializeObject(newImages);
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
streamWriter.Write(imagesJson);
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
My Json from this code looks like this:
I see the difference between mine and the one from the documentation, but I dont know how to change my json correctly.
Any solutions?
So that nobody had a solution, i tried something around and find a way to achieve what i need. I made a new Attachment and added each image manually.
Here is an example of the first image:
Attachments attBuffer = new Attachments();
using (imagesFromApi[0])
{
using (MemoryStream m = new MemoryStream())
{
partImgs[0].Save(m, partImgs[0].RawFormat);
byte[] imageBytes = m.ToArray();
// Convert byte[] to Base64 String
base64String = Convert.ToBase64String(imageBytes);
}
}
attBuffer.Hood = new Hood()
{
content_type = "image/jpeg",
data = base64String,
};
As you can see, i created any of my images as a class and then mapped the list to it. I think this is not the best way, but it works for me, so better than nothing.
Hope it helps you as well.
This question already has an answer here:
FromBase64String/UTF Encoding
(1 answer)
Closed 2 years ago.
I am trying to download a PDF file and encode it in UTF-8 format and then transform it back into a Base64 to attach it to a MailMessage, however I get an exception when passing the string to Base64.
exception
The input is not a valid Base-64 string as it contains a non-base 64 character...
my code...
try
{
if (attachment.Uri.Contains("http") || attachment.Uri.Contains("https"))
{
byte[] contentByte = null;
using (var webClient = new WebClient())
{
webClient.UseDefaultCredentials = true;
Uri uri = new Uri(attachment.Uri);
contentByte = webClient.DownloadData(uri);
}
MemoryStream memStream = new MemoryStream(contentByte);
String fullString = Encoding.UTF8.GetString(memStream.ToArray());
String stringData = fullString.Split(',')[1];
byte[] byteData = System.Convert.FromBase64String(stringData);
MemoryStream streamData = new MemoryStream(byteData);
Attachment attachmentDoc = new Attachment(streamData, fileName);
mail.Attachments.Add(attachmentDoc);
}
}
catch (Exception ex)
{
notificationLog.Error.Write(String.Format("Sendmail error. Attachment not found: " + attachment.FileName));
}
You are going about this the wrong way.
You are trying to decode the PDF as UTF-8 (which it is not) to UTF-16, and then decode that UTF-16 as Base64 (which it is not) to a byte array, then attach those bytes to the email. That is the complete opposite of what you need.
Base64 operates on bytes, not strings/characters. There is no need to encode a PDF (a binary file) to UTF-8 before encoding it in Base64. Just encode the PDF bytes as-is straight to Base64, eg:
try
{
if (attachment.Uri.StartsWith("http:") || attachment.Uri.StartsWith("https:"))
{
byte[] contentByte = null;
using (var webClient = new WebClient())
{
webClient.UseDefaultCredentials = true;
Uri uri = new Uri(attachment.Uri);
contentByte = webClient.DownloadData(uri);
}
String stringData = System.Convert.ToBase64String(contentByte);
MemoryStream memStream = new MemoryStream(Encoding.ASCII.GetBytes(stringData));
Attachment attachmentDoc = new Attachment(memStream, fileName);
mail.Attachments.Add(attachmentDoc);
}
}
catch (Exception ex)
{
notificationLog.Error.Write(String.Format("Sendmail error. Attachment not found: " + attachment.FileName));
}
However, using this approach, the receiver won't be able to decode the PDF correctly, because it won't know the PDF bytes were encoded in Base64.
Fortunately, the Attachment class can handle the Base64 for you, and notify the receiver of the encoding. Just give the Attachment the raw PDF bytes as-is, and set its TransferEncoding property to Base64, eg:
try
{
if (attachment.Uri.StartsWith("http:") || attachment.Uri.StartsWith("https:"))
{
byte[] contentByte = null;
using (var webClient = new WebClient())
{
webClient.UseDefaultCredentials = true;
Uri uri = new Uri(attachment.Uri);
contentByte = webClient.DownloadData(uri);
}
MemoryStream memStream = new MemoryStream(contentByte);
Attachment attachmentDoc = new Attachment(memStream, fileName);
attachmentDoc.TransferEncoding = TransferEncoding.Base64;
mail.Attachments.Add(attachmentDoc);
}
}
catch (Exception ex)
{
notificationLog.Error.Write(String.Format("Sendmail error. Attachment not found: " + attachment.FileName));
}
How do you convert an image from a path on the user's computer to a base64 string in C#?
For example, I have the path to the image (in the format C:/image/1.gif) and would like to have a data URI like data:image/gif;base64,/9j/4AAQSkZJRgABAgEAYABgAAD.. representing the 1.gif image returned.
Try this
using (Image image = Image.FromFile(Path))
{
using (MemoryStream m = new MemoryStream())
{
image.Save(m, image.RawFormat);
byte[] imageBytes = m.ToArray();
// Convert byte[] to Base64 String
string base64String = Convert.ToBase64String(imageBytes);
return base64String;
}
}
Get the byte array (byte[]) representation of the image, then use Convert.ToBase64String(), st. like this:
byte[] imageArray = System.IO.File.ReadAllBytes(#"image file path");
string base64ImageRepresentation = Convert.ToBase64String(imageArray);
To convert a base64 image back to a System.Drawing.Image:
var img = Image.FromStream(new MemoryStream(Convert.FromBase64String(base64String)));
Since most of us like oneliners:
Convert.ToBase64String(File.ReadAllBytes(imageFilepath));
If you need it as Base64 byte array:
Encoding.ASCII.GetBytes(Convert.ToBase64String(File.ReadAllBytes(imageFilepath)));
This is the class I wrote for this purpose:
public class Base64Image
{
public static Base64Image Parse(string base64Content)
{
if (string.IsNullOrEmpty(base64Content))
{
throw new ArgumentNullException(nameof(base64Content));
}
int indexOfSemiColon = base64Content.IndexOf(";", StringComparison.OrdinalIgnoreCase);
string dataLabel = base64Content.Substring(0, indexOfSemiColon);
string contentType = dataLabel.Split(':').Last();
var startIndex = base64Content.IndexOf("base64,", StringComparison.OrdinalIgnoreCase) + 7;
var fileContents = base64Content.Substring(startIndex);
var bytes = Convert.FromBase64String(fileContents);
return new Base64Image
{
ContentType = contentType,
FileContents = bytes
};
}
public string ContentType { get; set; }
public byte[] FileContents { get; set; }
public override string ToString()
{
return $"data:{ContentType};base64,{Convert.ToBase64String(FileContents)}";
}
}
var base64Img = new Base64Image {
FileContents = File.ReadAllBytes("Path to image"),
ContentType="image/png"
};
string base64EncodedImg = base64Img.ToString();
You can easily pass the path of the image to retrieve the base64 string
public static string ImageToBase64(string _imagePath)
{
string _base64String = null;
using (System.Drawing.Image _image = System.Drawing.Image.FromFile(_imagePath))
{
using (MemoryStream _mStream = new MemoryStream())
{
_image.Save(_mStream, _image.RawFormat);
byte[] _imageBytes = _mStream.ToArray();
_base64String = Convert.ToBase64String(_imageBytes);
return "data:image/jpg;base64," + _base64String;
}
}
}
Hope this will help.
You can use Server.Map path to give relative path and then you can either create image using base64 conversion or you can just add base64 string to image src.
byte[] imageArray = System.IO.File.ReadAllBytes(Server.MapPath("~/Images/Upload_Image.png"));
string base64ImageRepresentation = Convert.ToBase64String(imageArray);
This code works well with me on DotNet Core 6
using (Image image = Image.FromFile(path))
{
using (MemoryStream m = new MemoryStream())
{
image.Save(m, ImageFormat.Jpeg);
byte[] imageBytes = m.ToArray();
// Convert byte[] to Base64 String
string base64String = Convert.ToBase64String(imageBytes);
// In my case I didn't find the part "data:image/png;base64,", so I added.
return $"data:image/png;base64,{base64String}";
}
}
That way it's simpler, where you pass the image and then pass the format.
private static string ImageToBase64(Image image)
{
var imageStream = new MemoryStream();
try
{
image.Save(imageStream, System.Drawing.Imaging.ImageFormat.Bmp);
imageStream.Position = 0;
var imageBytes = imageStream.ToArray();
var ImageBase64 = Convert.ToBase64String(imageBytes);
return ImageBase64;
}
catch (Exception ex)
{
return "Error converting image to base64!";
}
finally
{
imageStream.Dispose;
}
}
Based on top voted answer, updated for C# 8. Following can be used out of the box. Added explicit System.Drawing before Image as one might be using that class from other namespace defaultly.
public static string ImagePathToBase64(string path)
{
using System.Drawing.Image image = System.Drawing.Image.FromFile(path);
using MemoryStream m = new MemoryStream();
image.Save(m, image.RawFormat);
byte[] imageBytes = m.ToArray();
tring base64String = Convert.ToBase64String(imageBytes);
return base64String;
}
The following piece of code works for me:
string image_path="physical path of your image";
byte[] byes_array = System.IO.File.ReadAllBytes(Server.MapPath(image_path));
string base64String = Convert.ToBase64String(byes_array);
The reverse of this for the googlers arriving here (there is no SO quesion/answer to that)
public static byte[] BytesFromBase64ImageString(string imageData)
{
var trunc = imageData.Split(',')[1];
var padded = trunc.PadRight(trunc.Length + (4 - trunc.Length % 4) % 4, '=');
return Convert.FromBase64String(padded);
}
Something like that
Function imgTo64(ByVal thePath As String) As String
Dim img As System.Drawing.Image = System.Drawing.Image.FromFile(thePath)
Dim m As IO.MemoryStream = New IO.MemoryStream()
img.Save(m, img.RawFormat)
Dim imageBytes As Byte() = m.ToArray
img.Dispose()
Dim str64 = Convert.ToBase64String(imageBytes)
Return str64
End Function
I am trying to generate a pdf using the Reporting services 2005 webservice. I have the pdf generation part working, but I am not sure how to get a "physical" pdf that I can attach to an email before sending it on its way.
I have created the pdf following this guide: http://www.codeproject.com/KB/reporting-services/PDFUsingSQLRepServices.aspx
public void RenderPdf(string rptMemo, string emailAddress )
{
// Prepare Render arguments
string historyID = null;
string deviceInfo = null;
string format = "PDF";
Byte[] results;
string encoding = String.Empty;
string mimeType = String.Empty;
string extension = String.Empty;
Rse2005.Warning[] warnings = null;
string[] streamIDs = null;
//Credentials that will be passed to reporting services
Rse2005.ReportExecutionService rsExec = new Rse2005.ReportExecutionService();
rsExec.Credentials = new NetworkCredential("username", "password", "domain");
//Report is called "Report1", it takes a parameter called "Id"
Rse2005.ExecutionInfo ei = rsExec.LoadReport("/Reports/Report1", historyID);
Rse2005.ParameterValue[] rptParameters = new Rse2005.ParameterValue[1];
rptParameters[0] = new Rse2005.ParameterValue();
rptParameters[0].Name = "Id";
rptParameters[0].Value = RptMemo;
//render the PDF
rsExec.SetExecutionParameters(rptParameters, "en-us");
results = rsExec.Render(format, deviceInfo, out extension, out encoding, out mimeType, out warnings, out streamIDs);
HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=DetailedQuote.pdf");
HttpContext.Current.Response.OutputStream.Write(results, 0, results.Length);
//This is very important if you want to directly download from stream instead of file.
HttpContext.Current.Response.End();
}
From this point I am able to call the RenderPdf method and I am prompted to open/save/cancel the file. I understand how to send an email with an attachment from the harddrive but I am not sure how to make results[] into a format I can handle.
thanks in advance
You should save the pdf to disk or memory and then use System.Net.Mail to send it
Here is a quick link from google.
http://www.systemnetmail.com/faq/3.4.2.aspx
You can write results from your example to a memory stream like so
var memStream = new MemoryStream();
memStream.Write(results, 0 , results.Length);
You should remove these 3 lines from your code
HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=DetailedQuote.pdf");
HttpContext.Current.Response.OutputStream.Write(results, 0, results.Length);
HttpContext.Current.Response.End();
Create a MemoryStream (reference) from the results byte array, then add the stream to an attachment with a ContentType, and add the attachment to the Attachments collection on the MailMessage.
using (MemoryStream ms = new MemoryStream(results, 0 , results.Length, false, true))
{
MailMessage msg = new MailMessage(...);
ContentType ct = new ContentType()
{
MediaType = MediaTypeNames.Application.Octet,
Name = "DetailedQuote.pdf"
};
Attachment att = new Attachment(ms, ct);
msg.Attachments.Add(att);
}