31

I'd like to create an email from a Javascript web application. I'm completely aware of the many SO questions on this (e.g. Open Outlook HTML with Chrome). There are problems with the typical answers:

  1. Mailto: link: This will let you create an email, but only in plain text (no HTML) and it does not allow for attachments.

  2. Activex: IE only, my application needs to run in Firefox and Chrome too. FF & Chrome plug-ins to allow ActiveX are security hazards and seem to be buggy.

  3. Server-side sends via SMTP: The email does not end up in the "Sent" folder for the user. Plus hurdles letting the user edit HTML in the browser and attach files.

  4. Create an Outlook .MSG file: There seem to be no libraries and little written about doing this. Apparently the file format actually has an entire FAT file storage system embedded.

Key differences between many other SO questions and mine:

  • I do have access to the client machines, so I could install helper applications or add-ins, change settings as needed, etc.
  • The interface does not need to actually send the mail, it only needs to set it up for the user.
  • I also need to be able to give the email an attachment from JS (e.g. a PDF).

I cannot be the first web app developer to face this and yet I'm unable to find a solution either commercial or open source.

Update:

I used the EML file method and it works well so far. Here's my JS code to create and trigger it:

var emlContent = "data:message/rfc822 eml;charset=utf-8,";
emlContent += 'To: '+emailTo+'\n';
emlContent += 'Subject: '+emailSubject+'\n';
emlContent += 'X-Unsent: 1'+'\n';
emlContent += 'Content-Type: text/html'+'\n';
emlContent += ''+'\n';
emlContent += htmlDocument;

var encodedUri = encodeURI(emlContent); //encode spaces etc like a url
var a = document.createElement('a'); //make a link in document
var linkText = document.createTextNode("fileLink");
a.appendChild(linkText);
a.href = encodedUri;
a.id = 'fileLink';
a.download = 'filename.eml';
a.style = "display:none;"; //hidden link
document.body.appendChild(a);
document.getElementById('fileLink').click(); //click the link
Community
  • 1
  • 1
James Bell
  • 889
  • 2
  • 10
  • 16
  • Your question is somewhat ambiguous. Your title and tags indicate you want to use JavaScript, but your "key differences" state that you can use helper application and add-ins, which are not (necessarily) JavaScript. It appears as though you want us to do some searching for you to find a solution, which is generally a bad fit for SO. – Heretic Monkey Jan 14 '15 at 22:19
  • ...but I would be using JavaScript to create the message and whatever else was needed to interface with some unknown solution. I've hunted high and low myself for a solution. I did not ask anyone else to look for me, I asked if someone had an approach that I had not thought of. – James Bell Jan 15 '15 at 13:37
  • I like the approach, it adheres to browser sandbox rules (the user doesn't have to open the EML file they download) whilst appearing to give exactly what is needed. I will definitely find a use for this technique! – Falkayn Apr 24 '15 at 01:44
  • @James Bell Can you please provide your filename.eml file? I am interesting how you are adding attachments. – Yuriy N. Feb 07 '16 at 11:14
  • @yurin The .EML file works for passing an HTML email to Outlook, but I could not find any way to add an attachment. – James Bell Feb 08 '16 at 17:48
  • 1
    Unpleasant update: Chrome (since about v.46) has begun flagging .EML files as possibly malicious. No idea what horrors a *text file* could cause but I assume they had their reasons. – James Bell Jun 29 '16 at 20:03

6 Answers6

28

MSG file format is documented, but it is certainly not fun... Why not create an EML (MIME) file?

The suggestion is to use the EML (MIME) format. According to the OP, they considered the MSG file format (#4), but were discouraged by its complexity and lack of JS libraries that process that format. If MSG file was considered, MIME is a much better choice - it is text based, so no special libraries are required to create it. Outlook will be able to open it just as easily as an MSG file.

To make sure EML message is treated as an unsent message by Outlook, set the X-Unsent MIME header to 1.


The simplest EML file would look like the following:

To: Joe The User <joe@domain.demo>
Subject: Test EML message
X-Unsent: 1
Content-Type: text/html

<html>
<body>
Test message with <b>bold</b> text.
</body>
</html>
Dmitry Streblechenko
  • 62,942
  • 4
  • 53
  • 78
  • 1
    This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. – NicolasMoise Jan 14 '15 at 21:36
  • 2
    No offense Nicolas, you do sound like a native English speaker, and I am pretty sure you realize that my suggestion is to use the MIME file format. I am sure you can see that "Why not create an EML (MIME) file?" is a polite way of saying "You really need to use the EML (MIME) format". – Dmitry Streblechenko Jan 14 '15 at 22:21
  • Have you tried this approach, and did it work? What resources did you use to learn the format? – James Bell Jan 15 '15 at 13:39
  • I am not a JavaScript developer, I work with Outlook. Try the sample EML file above. EML/MIME format is documented in RTC822: http://tools.ietf.org/html/rfc822 – Dmitry Streblechenko Jan 15 '15 at 13:55
  • 3
    This idea panned out and does indeed give me a way to make Outlook HTML emails. I have not tried attachments but this solves my immediate need very nicely. Props to @CalvT for developing it more. – James Bell Jan 28 '15 at 21:57
  • 1
    Kudos for the "X-Unsent: 1" - just what I was looking for.Thx – Marc Nov 30 '16 at 07:59
  • - .eml files are not supported in Outlook 2016. – Gintas K Jan 04 '19 at 16:23
  • 1
    @Gintas K - of course they are supported by Outlook 2016. Create an EML file and open it from Windows Explorer. – Dmitry Streblechenko Jan 04 '19 at 21:53
  • @DmitryStreblechenko Or is it Office365 taht doesn't support it? I get "You have a newer version of Office installed ... pleasse remove these new products and try again." when trying to open .eml files.. – Gintas K Jan 07 '19 at 10:47
  • Did you end up with two version of Office installed somehow? Have you tried to reinstall Office? Do you get the same problem with MSG files? – Dmitry Streblechenko Jan 07 '19 at 13:29
  • @DmitryStreblechenko I've only got one version installed - 2016, which is part of the Office365 plan. MSG files are absolutely fine.. – Gintas K Jan 08 '19 at 16:06
  • Have you tried to reinstall Outlook? This does not seem to be related to the original question. You might want to ask your question at Super User. – Dmitry Streblechenko Jan 08 '19 at 18:03
  • Where is a good resource to see the specifications for *.eml files? I would like to read more about `Content-Type`, `X-Unsent`, and see what other options exist. Thank you! – NamedArray Aug 20 '21 at 16:07
  • You start at https://en.wikipedia.org/wiki/MIME and follow the links to RFCs for more complete details. – Dmitry Streblechenko Aug 20 '21 at 17:35
20

Using the idea of plain text eml files, I came up with this: http://jsfiddle.net/CalvT/un3hapej/

This is an edit of something I found - to create a .txt file then download it. As .eml files are practically .txt files, I figured this would work. And it does. I've left the textarea with the sample email in so you can easily test. When you click on create file, it then gives you a download link to download your .eml file. The only hurdle I can see is making the browser open the .eml file after it has been downloaded.

EDIT: And thinking about it, as you have access to the client machines, you could set the browser to always open files of that type. For instance in Chrome, you can click on the arrow beside the download and select always open files of this type.

Here's the code

HTML:

(function () {
var textFile = null,
  makeTextFile = function (text) {
    var data = new Blob([text], {type: 'text/plain'});

    if (textFile !== null) {
      window.URL.revokeObjectURL(textFile);
    }

    textFile = window.URL.createObjectURL(data);

    return textFile;
  };


  var create = document.getElementById('create'),
    textbox = document.getElementById('textbox');

  create.addEventListener('click', function () {
    var link = document.getElementById('downloadlink');
    link.href = makeTextFile(textbox.value);
    link.style.display = 'block';
  }, false);
})();
<textarea id="textbox" style="width: 300px; height: 200px;">
To: User <user@domain.demo>
Subject: Subject
X-Unsent: 1
Content-Type: text/html

<html>
<body>
Test message
</body>
</html>
  
</textarea>

<button id="create">Create file</button>
  
<a download="message.eml" id="downloadlink" style="display: none">Download</a>
CalvT
  • 3,123
  • 6
  • 37
  • 54
  • I am planning to develop this futher as it interests me – CalvT Jan 16 '15 at 01:12
  • Did you discovered how to add attachments via eml file? – Yuriy N. Feb 07 '16 at 11:58
  • 6
    Is it possible to open the eml file in outlook directly without downloading it in the browser ? – Santhosh Jun 20 '16 at 10:41
  • I have a similar requirement and have followed this approach,however I have base64 encoded images in the email content.When the eml is generated the size of the image reduces. Also the fiddler does not work with Microsoft Edge Browser version Version 90.0.818.56.Below is the link created for same -> https://stackoverflow.com/questions/67523117/image-size-reduced-when-base64encoded-image-is-embedded-in-rich-email-containing – AnitaS May 17 '21 at 11:03
  • @AnitaS the fiddle works for me on Edge 90.0.818.62, so maybe your issue is a local one? – CalvT May 18 '21 at 11:15
  • @CalvT I am not sure on that, though it works on other Edge versions that I could test.However with base64 encoded image embedded in html,this has issues rendering the image. https://jsfiddle.net/AnitaSS/g7jnvuab/1 – AnitaS May 18 '21 at 11:55
13

Nobody seems to have answered the attachment question, so here's my solution: create the EML as a multipart/mixed message.

Content-Type: multipart/mixed; boundary=--boundary_text_string

With this, you can have multiple parts in your email. Multiple parts let you add attachments, like this.

Content-Type: application/octet-stream; name=demo.pdf
Content-Transfer-Encoding: base64
Content-Disposition: attachment

Start with your email headers, then add your boundary, then the part contents (newline locations are very important, clients won't parse your file correctly otherwise). You can add multiple parts. Below is an example. Note that the last boundary is different from the others (2 dashes at the end).

To: Demo-Recipient <demo@demo.example.com>
Subject: EML with attachments
X-Unsent: 1
Content-Type: multipart/mixed; boundary=--boundary_text_string

----boundary_text_string
Content-Type: text/html; charset=UTF-8

<html>
<body>
<p>Example</p>
</body>
</html>

----boundary_text_string
Content-Type: application/octet-stream; name=demo.txt
Content-Transfer-Encoding: base64
Content-Disposition: attachment
ZXhhbXBsZQ==

----boundary_text_string
Content-Type: application/octet-stream; name=demo.log
Content-Transfer-Encoding: base64
Content-Disposition: attachment
ZXhhbXBsZQ==

----boundary_text_string--

This gives you a eml file with two attachments. See RFC 1371 if you want to know more specifics on how this works.

korhojoa
  • 131
  • 2
  • 2
3

I had encoding problem when creating an .eml file with non-english characters and then opening it in Outlook. The problem was that I put the "charset=" to the wrong place and did not put the quotes (") around the encoding. The solution:

function createShiftReportEmail() {
    const title = "Shift Összefoglaló";
    const body = "ÁÉŐÚŰÓÜÖÍűáéúőóöí";

    const emlContent = new Blob([`data:message/rfc822 eml,\nSubject: ${title}\nX-Unsent: 1\nContent-Type: text/plain;charset="utf-8"\n\n${body}`]);

    if (!document.querySelector('#downloadEmail')) {
        document.body.insertAdjacentHTML('beforeend', '<a id="downloadEmail" download="ShiftReport.eml" style="display: none">Download</a>');
    }
    const downloadBtn = document.querySelector('#downloadEmail');
    downloadBtn.href = URL.createObjectURL(emlContent);
    downloadBtn.click();
}

Edit: Turns out quotes (") are not even necessary. Only the placement was wrong for me.

0

After try korhojoa answer, it's not working and need some adjustments:

To: Demo-Recipient <demo@demo.example.com>
Subject: EML with attachments
X-Unsent: 1
Content-Type: multipart/mixed; boundary=--boundary_text_string

----boundary_text_string
Content-Type: text/html; charset=UTF-8

<html>
<body>
<p>Example</p>
</body>
</html>

----boundary_text_string
Content-Type: application/octet-stream; name=demo.txt
Content-Transfer-Encoding: base64
Content-Disposition: attachment

ZXhhbXBsZQ==

----boundary_text_string
Content-Type: application/octet-stream; name=demo.log
Content-Transfer-Encoding: base64
Content-Disposition: attachment

ZXhhbXBsZQ==

----boundary_text_string--
0

JS libraries to make a life simpler (no need to invent a wheel):

  • compose EML file: nodemailer/lib/mail-composer
  • parse EML file: mailparser
  • parse MSG file: @kenjiuno/msgreader
mirik
  • 356
  • 4
  • 18