I need to embed an image in e-mail. How do I do it?
I do not want to use third party tool, nor am I interested in language specific answer (but it is PHP, in case you are wondering).
I am merely interested in format of resulting e-mail body.
As you are aware, everything passed as email message has to be textualized.
You must create an email with a multipart/mime message.
If you're adding a physical image, the image must be base 64 encoded and assigned a Content-ID (cid). If it's an URL, then the <img /> tag is sufficient (the url of the image must be linked to a Source ID).
A Typical email example will look like this:
From: foo1atbar.net
To: foo2atbar.net
Subject: A simple example
Mime-Version: 1.0
Content-Type: multipart/related; boundary="boundary-example"; type="text/html"
--boundary-example
Content-Type: text/html; charset="US-ASCII"
... text of the HTML document, which might contain a URI
referencing a resource in another body part, for example
through a statement such as:
<IMG SRC="cid:foo4atfoo1atbar.net" ALT="IETF logo">
--boundary-example
Content-Location: CID:somethingatelse ; this header is disregarded
Content-ID: <foo4atfoo1atbar.net>
Content-Type: IMAGE/GIF
Content-Transfer-Encoding: BASE64
R0lGODlhGAGgAPEAAP/////ZRaCgoAAAACH+PUNv
cHlyaWdodCAoQykgMTk5LiBVbmF1dGhvcml6ZWQgZHV
wbGljYXRpb24gcHJvaGliaXRlZC4A etc...
--boundary-example--
As you can see, the Content-ID: <foo4atfoo1atbar.net> ID is matched to the <IMG> at SRC="cid:foo4atfoo1atbar.net". That way, the client browser will render your image as a content and not as an attachement.
the third way is to base64 encode the image and place it in a data: url
example:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACR0lEQVRYha1XvU4bQRD+bF/JjzEnpUDwCPROywPgB4h0PUWkFEkLposUIYyEU4N5AEpewnkDCiQcjBQpWLiLjk3DrnZnZ3buTv4ae25mZ+Z2Zr7daxljDGpg++Mv978Y5Nhc6+Di5tk9u7/bR3cjY9eOJnMUh3mg5y0roBjk+PF1F+1WCwCCJKTgpz9/ozjMg+ftVQQ/PtrB508f1OAcau8ADW5xfLRTOzgAZMPxTNy+YpDj6vaPGtxPgvpL7QwAtKXts8GqBveT8P1p5YF5x8nlo+n1p6bXn5ov3x9M+fZmjDGRXBXWH5X/Lv4FdqCLaLAmwX1/VKYJtIwJeYDO+dm3PSePJnO8vJbJhqN62hOUJ8QpoD1Au5kmIentr9TobAK04RyJEOazzjV9KokogVRwjvm6652kniYRJUBrTkft5bUEAGyuddzz7noHALBYls5O09skaE+4HdAYruobUz1FVI6qcy7xRFW95A915pzjiTp6zj7za6fB1lay1/Ssfa8/jRiLw/n1k9tizl7TS/aZ3xDakdqUByR/gDcF0qJV8QAXHACy+7v9wGA4ngWLVskDo8kcg4Ot8FpGa8PV0I7MyeWjq53f7Zrer3nyOLYJpJJowgN+g9IExNNQ4vLFskwyJtVrd8JoB7g3b4rz66dIpv7UHqg611xw/0om8QT7XXBx84zheCbKGui2U9n3p/YAlSVyqRqc+kt+mCyWJTSeoMGjOQciOQDXA6kjVTsL6JhpYHtA+wihPaGOWgLqnVACPQua4j8NK7bPLP4+qQAAAABJRU5ErkJggg==" width="32" height="32">
Here is how to get the code for an embedded image without worrying about any files or base64 statements or mimes (it's still base64, but you don't have to do anything to get it). I originally posted this same answer in this thread, but it may be valuable to repeat it in this one, too.
To do this, you need Mozilla Thunderbird, you can fetch the html code for an image like this:
Copy a bitmap to clipboard.
Start a new email message.
Paste the image. (don't save it as a draft!!!)
Double-click on it to get to the image settings dialogue.
Look for the "image location" property.
Fetch the code and wrap it in an image tag, like this:
You should end up with a string of text something like this:
<img src="data:image/png;base64,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" alt="" height="211" width="213">
You can wrap this up into a string variable and place this absolutely anywhere that you would present an html email message - even in your email signatures. The advantage is that there are no attachments, and there are no links. (this code will display a lizard)
A picture is worth a thousand words:
Incidentally, I did write a program to do all of this for you. It's called BaseImage, and it will create the image code as well as the html for you. Please don't consider this self-promotion; I'm just sharing a solution.
Correct way of embedding images into Outlook and avoiding security problems is the next:
Use interop for Outlook 2003;
Create new email and set it save folder;
Do not use base64 embedding, outlook 2007 does not support it; do not reference files on your disk, they won't be send; do not use word editor inspector because you will get security warnings on some machines;
Attachment must have png/jpg extension. If it will have for instance tmp extension - Outlook will warn user;
Pay attention how CID is generated without mapi;
Do not access properties via getters or you will get security warnings on some machines.
public static void PrepareEmail()
{
var attachFile = Path.Combine(
Application.StartupPath, "mySuperImage.png"); // pay attention that image must not contain spaces, because Outlook cannot inline such images
Microsoft.Office.Interop.Outlook.Application outlook = null;
NameSpace space = null;
MAPIFolder folder = null;
MailItem mail = null;
Attachment attachment = null;
try
{
outlook = new Microsoft.Office.Interop.Outlook.Application();
space = outlook.GetNamespace("MAPI");
space.Logon(null, null, true, true);
folder = space.GetDefaultFolder(OlDefaultFolders.olFolderSentMail);
mail = (MailItem) outlook.CreateItem(OlItemType.olMailItem);
mail.SaveSentMessageFolder = folder;
mail.Subject = "Hi Everyone";
mail.Attachments.Add(attachFile, OlAttachmentType.olByValue, 0, Type.Missing);
// Last Type.Missing - is for not to show attachment in attachments list.
string attachmentId = Path.GetFileName(attachFile);
mail.BodyFormat = OlBodyFormat.olFormatHTML;
mail.HTMLBody = string.Format("<br/><img src=\'cid:{0}\' />", attachmentId);
mail.Display(false);
}
finally
{
ReleaseComObject(outlook, space, folder, mail, attachment);
}
}
Actually, there are two ways to include images in email.
The first way ensures that the user will see the image, even if in some cases it’s only as an attachment to the message. This method is exactly what we call as “embedding images in email" in daily life.
Essentially, you’re attaching the image to the email. The plus side is that, in one way or another, the user is sure to get the image. While the downside is two fold. Firstly, spam filters look for large, embedded images and often give you a higher spam score for embedding images in email (Lots of spammers use images to avoid having the inappropriate content in their emails read by the spam filters.). Secondly, if you pay to send your email by weight or kilobyte, this increases the size of your message. If you’re not careful, it can even make your message too big for the parameters of the email provider.
The second way to include images (and the far more common way) is the same way that you put an image on a web page. Within the email, you provide a url that is the reference to the image’s location on your server, exactly the same way that you would on a web page. This has several benefits. Firstly, you won’t get caught for spamming or for your message “weighing” too much because of the image. Secondly, you can make changes to the images after the email has been sent if you find errors in them. On the flip side, your recipient will need to actively turn on image viewing in their email client to see your images.
Generally I handle this by setting up an HTML formatted SMTP message, with IMG tags pointing to a content server. Just make sure you have both text and HTML versions since some email clients cannot support HTML emails.
Related
I have a JavaScript file saved to a google cloud storage bucket. it includes Arabic such as
["كانون الثاني", "فبراير", "مارس", "أبريل", "أيار", "حزيران","تموز", "آب", "أيلول", "تشرين الأول", "تشرين الثاني", "كانون الاول"];
when the file is served, these would look like :
["كانونالثاني","ÙÂبراير","مارس","أبريل","أيار","ØÂزيران","تموز","آب","أيلول","تشرينالأول","تشرينالثاني","كانونالاول"]
although the script is being called with charset="utf-8". but even opening the file through the public link (in chrome). shows the scrambled text. where as if I open the file locally using chrome as well, I can see the Arabic literals.
I need to have these Arabic literals served and displayed as they are expected
Posting as a community wiki based on the comment of #JosefZ.
You face a double mojibake case (example in Python for its universal intelligibility): print('كانون الثاني'.encode( 'utf-8').decode( 'cp1252').encode( 'utf-8').decode( 'cp1252')) returns كانونالثانÙŅ
To add:
Make sure that every pass the content goes through is UTF-8 clean or preserves the original content byte-for-byte exactly. That includes setting Content-type headers appropriately (Likely: text/html; charset=utf-8). This precise issue is why it is recommended to use UTF-8 for all the things.
We have an InDesign Server service that changes text, images, colours etc in documents according to user input. When done, it outputs either an INDD package (zipped directory) or a PDF.
One of our clients requires all output to be in CMYK, according to their own .icc colour profile. I can get IDS to attach the colour profile to the file no problem, like this:
// Set CMYK profile
if(inputs['cmyk_profile'] !== undefined && inputs['cmyk_profile']) {
app.colorSettings.cmykPolicy = ColorSettingsPolicy.PRESERVE_EMBEDDED_PROFILES;
document.cmykPolicy = ColorSettingsPolicy.PRESERVE_EMBEDDED_PROFILES;
document.cmykProfile = inputs['cmyk_profile'];
//document.printPreferences.colorOutput = ColorOutputModes.COMPOSITE_CMYK;
}
I confess, though, that I am a bit of a newbie and the PRESERVE_EMBEDDED_PROFILES lines are only a vague guess of what I think should be happening. I also cannot get the last, commented-out, line to work because it throws the error: "Invalid parameter". According to the docs, this instance variable is "not valid when a device-independent PPD is specified" although I don't see why not.
My main problem is that the user-inputted images and colours can be in RGB format, and they need to be converted to CMYK, in that specific colour profile. (I have been told that simply adding the profile to the file isn't enough - I have to convert the assets as well)
I am also trying to enforce CMYK when converting to PDF too, like this:
// Set CMYK if document has it
if(document.cmykPolicy)
{
app.pdfExportPreferences.pdfDestinationProfile = PDFProfileSelector.USE_DOCUMENT;
app.pdfExportPreferences.pdfColorSpace = PDFColorSpace.CMYK;
}
else
{
app.pdfExportPreferences.pdfColorSpace = PDFColorSpace.UNCHANGED_COLOR_SPACE;
}
// export pdf...
document.exportFile(ExportFormat.pdfType, myFile, preset);
But I have been told that the resulting PDF file is also RGB.
Is there any relatively painless way of doing this?
I've a DataSnap server method
function TServerMethods.GetFile(filename): TStream
returning a file.
In my test case the file is a simple .PDF.
I'm sure this function works fine, as I'm able to open files on ObjectiveC client side app's where I've used my own http call to the DataSnap method (no Delphi proxy).
The stream is read from ASIHttpRequest object and saved as local file, then loaded and regulary shown in standard pdf reader.
I do not kown how exactly ASIHttpRequest manages the returned data.
But on JavaScript client side where I use standard
stream = ServerMethods().GetFile('test.pdf')
JavaScript function, as provided from DataSnap proxy itself, I do not figure out how to show the .pdf data to the user.
Using
window.open().document.write(stream);
a new browser window opens with textual raw data ( %PDF-1.5 %âãÏÓ 1 0 obj << /Type /Catalog /Pages 2 0 R …..)
With
window.open("data:application/pdf;base64," +stream);
I get an empty new browser page.
With
window.open("data:application/pdf," +stream);
or
document.location = 'data:application/pdf,'+encodeURIComponent(serverMethods().GetFile('test'));
I get an new browser page with pdf empry reader and alert “This PDF document could not be displayed correctly”
Nothing changes adding:
GetInvocationMetadata().ResponseContentType := 'application/pdf';
into the DataSnap function.
I've no other ideas...
EDIT
The task is for a general file download, not only PDF. PDF is a test only. GetFile have to manage .pdf, .xlsx, .docx, .png, .eml, etc...
Your server side code works as expected once you set the ResponseContentType. You can test this by calling the method directly from a browser. Change the class name to match the one you're using:
http://localhost:8080/datasnap/rest/TServerMethods1/GetFile/test.pdf
I'm sure there's a way to display the stream properly on the browser side, but I'm not sure what that is. Unless you're doing something special with the stream, I'd recommend getting the document directly or using a web action and getting out of the browser's way. Basically what mjn suggested.
I can think of a couple of solutions.
1) A quick way would be to allow access to the documents directly.
In the WebFileDispatcher, add a WebFileExtension. Select .pdf and it will fill in the mime type for you. Assuming your pdf documents are in the "docs" folder, the url might look like this:
http://localhost:8080/docs/test.pdf
2) I would probably add an action on the web module. It's a little more involved, but it also gives me more control.
Using this url:
http://localhost:8080/getfile?filename=test.pdf
And code like this in the web action handler (no checking or error handling). The Content-Disposition header suggests a file name for the downloaded file:
procedure TWebModule1.WebModule1GetFileActionAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
lStream: TMemoryStream;
lFilename: string;
begin
lFilename := Request.QueryFields.Values['filename'];
lStream := TMemoryStream.Create;
lStream.LoadFromFile('.\Docs\' + lFilename);
lStream.Position := 0;
Response.ContentStream := lStream;
Response.ContentType := 'application/pdf';
Response.SetCustomHeader('Content-Disposition',
Format('attachment; filename="%s"', [lFilename]));
end;
I've have some javascript code that transforms XML with XSLT. I now want the user to be able to save that new XML (either by prompting them or throwing the new XML up as a file or something so that the user can then save it. Anybody know how to do that?
var xmldoc = new ActiveXObject("Microsoft.XMLDOM");
xmldoc.async = false;
xmldoc.loadXML(responseText); // responseText is xml returned from ajax call
//apply the xslt
var xsldoc = new ActiveXObject("Microsoft.XMLDOM");
xsldoc.async = false;
xsldoc.load("../xslt/ExtraWorkRequest.xslt");
var content = xmldoc.transformNode(xsldoc);
How do I get the user to save the XML (content) as a file?
By default, you can't. Browser isn't supposed to access your local disks for security reasons.
But, if you can ask your user to change it's security settings (and you should not to ask), you can to use FileSystemObject or even your Microsoft.XMLDOM.Save method.
You cannot do it with 100% client-side JavaScript with the default security settings. You'll need to implement some server-side logic. In your case, you'll be able to do the XML transformation server-side, as well.
http://www.bigresource.com/Tracker/Track-javascripts-ijfTJlI9/
http://support.microsoft.com/kb/q260519/
You could construct a data: URI with a media type of application/octet-stream.
function download (data, charset) {
if (!charset) {
charset = document.characterSet;
}
location.href = ["data:application/octet-stream;charset=",
charset, ",", encodeURIComponent(data)
].join("");
}
All browsers except IE support data: URIs. I think IE8 may support them, but only for images. For IE, a workaround could be to send the data to a server (including document.characterSet) and then load a page that has something like the following header:
Content-Type: application/xml; charset={document.characterSet}
Content-Disposition: attachment
If you want to give the file a name too, use Content-Disposition: attachment; filename=....
Also, for any of this to work, you have to convert your XML to a string first.
I do this with code snippets on my blog (user can click on the save button, and the snippet will come up in their default text editor, where they can tweak it and/or copy it into their app).
It works by putting all the textual data inside of a hidden field, and then submits it to a very simple server-side HTTP handler. The handler just grabs the hidden field value and spits it right back out in the response with the right content-disposition header, giving the user the open/save download prompt.
This is the only way I could get it to work.
On PHP, they have a way to restrict file size AFTER uploading, but not BEFORE uploading. I use the Malsup jQuery Form Plugin for my form posting, and it supports image file posting.
I was wondering if perhaps there's a restriction where I can set how many bytes can pass through that AJAX stream up to the server? That could permit me to check that file size and return an error if the file is too big.
By doing this on the client side, it blocks those newbies who take a 10MB photo shot from their Pentax and try to upload that.
This is a copy from my answers in a very similar question: How to check file input size with jQuery?
You actually don't have access to the filesystem (for example reading and writing local files). However, due to the HTML5 File API specification, there are some file properties that you do have access to, and the file size is one of them.
For this HTML:
<input type="file" id="myFile" />
try the following:
//binds to onchange event of your input field
$('#myFile').bind('change', function() {
//this.files[0].size gets the size of your file.
alert(this.files[0].size);
});
As it is a part of the HTML5 specification, it will only work for modern browsers (v10 required for IE) and I added here more details and links about other file information you should know: http://felipe.sabino.me/javascript/2012/01/30/javascipt-checking-the-file-size/
Old browsers support
Be aware that old browsers will return a null value for the previous this.files call, so accessing this.files[0] will raise an exception and you should check for File API support before using it
I don't think it's possible unless you use a flash, activex or java uploader.
For security reasons ajax / javascript isn't allowed to access the file stream or file properties before or during upload.
I tried it this way and I am getting the results in IE*, and Mozilla 3.6.16, didnt check in older versions.
<img id="myImage" src="" style="display:none;"><br>
<button onclick="findSize();">Image Size</button>
<input type="file" id="loadfile" />
<input type="button" value="find size" onclick="findSize()" />
<script type="text/javascript">
function findSize() {
if ( $.browser.msie ) {
var a = document.getElementById('loadfile').value;
$('#myImage').attr('src',a);
var imgbytes = document.getElementById('myImage').size;
var imgkbytes = Math.round(parseInt(imgbytes)/1024);
alert(imgkbytes+' KB');
}else {
var fileInput = $("#loadfile")[0];
var imgbytes = fileInput.files[0].fileSize; // Size returned in bytes.
var imgkbytes = Math.round(parseInt(imgbytes)/1024);
alert(imgkbytes+' KB');
}
}
</script>
Add Jquery library also.
I encountered the same issue. You have to use ActiveX or Flash (or Java). The good thing is that it doesn't have to be invasive. I have a simple ActiveX method that will return the size of the to-be-uploaded file.
If you go with Flash, you can even do some fancy js/css to cusomize the uploading experience--only using Flash (as a 1x1 "movie") to access it's file uploading features.
I found that Apache2 (you might want to also check Apache 1.5) has a way to restrict this before uploading by dropping this in your .htaccess file:
LimitRequestBody 2097152
This restricts it to 2 megabytes (2 * 1024 * 1024) on file upload (if I did my byte math properly).
Note when you do this, the Apache error log will generate this entry when you exceed this limit on a form post or get request:
Requested content-length of 4000107 is larger than the configured limit of 2097152
And it will also display this message back in the web browser:
<h1>Request Entity Too Large</h1>
So, if you're doing AJAX form posts with something like the Malsup jQuery Form Plugin, you could trap for the H1 response like this and show an error result.
By the way, the error number returned is 413. So, you could use a directive in your .htaccess file like...
Redirect 413 413.html
...and provide a more graceful error result back.
$(".jq_fileUploader").change(function () {
var fileSize = this.files[0];
var sizeInMb = fileSize.size/1024;
var sizeLimit= 1024*10;
if (sizeInMb > sizeLimit) {
}
else {
}
});
Try below code:
var sizeInKB = input.files[0].size/1024; //Normally files are in bytes but for KB divide by 1024 and so on
var sizeLimit= 30;
if (sizeInKB >= sizeLimit) {
alert("Max file size 30KB");
return false;
}
Like others have said, it's not possible with just JavaScript due to the security model of such.
If you are able to, I'd recommend one of the below solutions..both of which use a flash component for the client side validations; however, are wired up using Javascript/jQuery. Both work very well and can be used with any server-side tech.
http://www.uploadify.com/
http://swfupload.org/
It's not possible to verify the image size, width or height on the client side. You need to have this file uploaded on the server and use PHP to verify all this info.
PHP has special functions like: getimagesize()
list($width, $height, $type, $attr) = getimagesize("img/flag.jpg");
echo "<img src=\"img/flag.jpg\" $attr alt=\"getimagesize() example\" />";