Can an HTML Email Body Reference a File Sent as an Attachment (In The Same Email)

Can an HTML email body reference a file sent as an attachment (in the same email)?

No hacks needed. Use the cid: URI scheme

 --boundary-example 1
Content-Type: Text/HTML; charset=US-ASCII

to the other body part, for example through a statement such as:
<IMG SRC="cid:foo4*foo1@bar.net" ALT="IETF logo">

--boundary-example-1

Content-ID: <foo4*foo1@bar.net>
Content-Type: IMAGE/GIF
Content-Transfer-Encoding: BASE64

R0lGODlhGAGgAPEAAP/////ZRaCgoAAAACH+PUNvcHlyaWdodCAoQykgMTk5
NSBJRVRGLiBVbmF1dGhvcml6ZWQgZHVwbGljYXRpb24gcHJvaGliaXRlZC4A
etc...

--boundary-example-1--

HTML Code Link within an Email to an Email Attachment

Nope. Each mail client takes care of attachments individually, in their own way. If you could make it work in some clients, rest would fail.

If think that there would be more problems than use.

Is it possible to embed non-image attachments inline in an html email, like Outlook RTF/TNEF does?

I decided to be less lazy and try it myself...

The answer is yes, you can refer to non-image attachments within an html email using an <a href='cid:...'> . </a> tag and Outlook will open them. I'm using Outlook 2013 as my email client and Office365 as my server; mileage varies with different clients and maybe servers. But doesn't work so well if you don't use outlook...

Gmail

I tested sending to gmail too. Inline images work fine, but attachments don't. The <a> links are displayed but don't work, and if you refer to an attachment using a cid:... url within the body of the email gmail doesn't display it even with disposition:attachment :( Same behavior on the gmail iPhone app: inline images look fine, inline attachments don't display or open from <a> links.

iPhone Mail

iPhone's Mail app (connecting to Office 365) renders the <a> tags as links but they don't work. If you set the attachment disposition to 'attachment' (i.e. not 'inline') then the attachments are displayed at the bottom of the email, unlike gmail which hides them in this case. If you set attachment disposition to 'inline' then it hides the attachments.

So if you have gmail recipients/email clients you'll need to do something differently, perhaps even attaching files twice: once as disposition:inline (linked to within the body) and once as disposition:attachment. It's sad that Gmail doesn't display attachments that have disposition:attachment and are referred to using the cid, since that would at least mean there's a way to access them. If anyone has any suggestions do let me know!

Sample code

Here's the powershell I used for testing, using EWS. It sends an html email with

  • an embedded image (which never appears as 'an attachment')
  • a .pdf linked to with an <a> tag, marked as inline. In Outlook this doesn't appear as an attachment but can be accessed from the link. In both gmail and iOS Mail this isn't shown as an attachment and can't be accessed from the link.
  • a .docx file linked with an <a> tag and marked as an attachment. In Outlook this appears as an attachment and also can be accessed from the link. In gmail this isn't shown and doesn't work from the link. In iOS Mail this is shown as an attachment but can't be accessed from the link.
  • the same .docx file again marked as attachment and not linked with <a> tag. This is visible in Outlook, gmail, iOS Mail as an attachment.

powershell:

$to1 = 'your-email@gmail.com'
$to2 = 'your-email@your-domaincom'
$subject = 'Test email with embedded attachments'
$body = '
This email shows embedded attachments. Yay. <br/><br/>
Here is an image: <img src="cid:img1@your-domain.com" /><br/>
More amazingly, <a href="cid:att1@your-domain.com">here</a> is a pdf.<br/>
And <a href="cid:att2@your-domain.com">here</a> is a word doc!<br/><br/>
'
# fyi - the '@your-domain.com' in the id is optional but somewhere I read
# that email clients might like it more if it's included. Doesn't need to
# be a real domain.

# change these paths to something that exists
$image1Path = "C:\temp\an_image.jpg"
$attachment1Path = "C:\temp\some_file.pdf"
$attachment2Path = "C:\temp\some_doc.docx"

#prompt for Office365 creds
$Credential = Get-Credential

#Load the EWS Managed API Assembly - you need it installed first!!
Add-Type -Path 'C:\Program Files (x86)\Microsoft\Exchange\Web Services\2.1\Microsoft.Exchange.WebServices.dll'

#Instantiate the EWS service object
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService

#Set the credentials for Exchange Online
$service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials -ArgumentList $Credential.UserName, $Credential.GetNetworkCredential().Password

#Autodiscover doesn't seem to work for my office365; set it manually
$service.Url = 'https://outlook.office365.com/EWS/Exchange.asmx'
#This might work for you instead:
# $service.AutodiscoverUrl($Credential.UserName, {$true})

#Create the email message and set the Subject and Body
$message = New-Object Microsoft.Exchange.WebServices.Data.EmailMessage -ArgumentList $service
$message.Subject = $subject
$message.Body = $body
$null = $message.ToRecipients.Add($to1)
$null = $message.ToRecipients.Add($to2)
$att = $message.Attachments.AddFileAttachment($image1Path)
$att.ContentId = 'img1@your-domain.com'
$att.IsInline=$true
$att = $message.Attachments.AddFileAttachment($attachment1Path)
$att.ContentId = 'att1@your-domain.com'
$att.IsInline=$true
$att = $message.Attachments.AddFileAttachment($attachment2Path)
$att.ContentId = 'att2@your-domain.com'
$att.IsInline=$false

# add the same attachment again with a different name to see if it's
# rendered differently.
$att = $message.Attachments.AddFileAttachment('no_cid.docx', $attachment2Path)
$att.IsInline=$false

#Send the message and save a copy in the Sent Items folder
$message.SendAndSaveCopy()

And some handy articles:

  • Send Email from Exchange Online by Using PowerShell
  • Adding inline attachments by using the EWS Managed API 2.0

Send HTML email along with multiple file attachments?

First you need to add the text as an own BodyPart. Next your MimeMultipart needs to be set to the type related so you can have both, HTML-Text and some attachements. Then it should work to have both, attachements and text.

And the filename you pass to messageBodyPart.setFileName(filename) is the filename you see in the attachment name. So just leave out the path and you should just see abc.csv and tree.txt

public void sendEmail(final String to, final String from, final String cc, final String subject, final String body,
final String baseDirectory, final List<String> listOfFileNames) {
for (int i = 1; i <= 3; i++) { // retrying
try {
Session session = Session.getInstance(mailProperties, null);

Multipart multipart = new MimeMultipart("related");
MimeBodyPart bodyPart= new MimeBodyPart();

Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));

InternetAddress[] toAddress = InternetAddress.parse(to);
InternetAddress[] ccAddress = InternetAddress.parse(cc);

message.addRecipients(RecipientType.TO, toAddress);
message.addRecipients(RecipientType.CC, ccAddress);
message.setSubject(subject);

bodyPart.setText(body, "UTF-8", "html");
multipart.addBodyPart(bodyPart);

for (String file : listOfFileNames) {
String fileLocation = baseDirectory + "/" + file;
addAttachment(multipart, fileLocation, file);
}
message.setContent(multipart);
Transport.send(message, toAddress);
break;
} catch (Exception ex) {
// log exception
}
}
}

// this is used for attachment
private void addAttachment(final Multipart multipart, final String filepath, final String filename) throws MessagingException {
DataSource source = new FileDataSource(filepath);
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(filename);
multipart.addBodyPart(messageBodyPart);
}

using mailto to send email with an attachment

Nope, this is not possible at all. There is no provision for it in the mailto: protocol, and it would be a gaping security hole if it were possible.

The best idea to send a file, but have the client send the E-Mail that I can think of is:

  • Have the user choose a file
  • Upload the file to a server
  • Have the server return a random file name after upload
  • Build a mailto: link that contains the URL to the uploaded file in the message body

Embedding attached images in HTML emails

Be more specific on how you build the HTML mail message.

The result will be a multipart-MIME message with a text/html part (if you really do it right with an alternate part of type text/plain) and several images, which are then referenced from within the HTML.

See RFC 1813 and RFC 2378 for more information about content-id in mixed MIME and related data (referred by CID in the HTML source).

Send html email with embedded image and plain text with same image as attachment in C#

This code snippet works in outlook 2010 and gmail. I test the plain text email by temporarily putting the plain text part last in the email, which makes gmail use that.

It also demonstrates some other cool stuff such as email templates and tag substitution.


public void SendEmailWithPicture(string email, byte[] image)
{
string filename = "AttachmentName.jpg";

LinkedResource linkedResource = new LinkedResource(new MemoryStream(image), "image/jpg");
linkedResource.ContentId = filename;
linkedResource.ContentType.Name = filename;

this.Send(
EmailTemplates.sendpicture,
this.Subjects.SendPicture,
new List() { email },
this.ReplyTo,
tagValues: new Dictionary() { { "ImageAttachmentName", "cid:" + filename } },
htmlLinkedResources: new List() { linkedResource }
);
}

private void Send(EmailTemplates template, string subject, List to, string replyTo,
Dictionary tagValues = null, List attachments = null, List htmlLinkedResources = null)
{
try
{
MailMessage mailMessage = new MailMessage();

// Set up the email header.
to.ForEach(t => mailMessage.To.Add(new MailAddress(t)));
mailMessage.ReplyToList.Add(new MailAddress(replyTo));
mailMessage.Subject = subject;

string fullTemplatePath = Path.Combine(this.TemplatePath, EMAIL_TEMPLATE_PATH);

// Load the email bodies
var htmlBody = File.ReadAllText(Path.Combine(fullTemplatePath, Path.ChangeExtension(template.ToString(), "html")));
var textBody = File.ReadAllText(Path.Combine(fullTemplatePath, Path.ChangeExtension(template.ToString(), "txt")));

// Replace the tags in the emails
if (tagValues != null)
{
foreach (var entry in tagValues)
{
string tag = "{{" + entry.Key + "}}";

htmlBody = htmlBody.Replace(tag, entry.Value);
textBody = textBody.Replace(tag, entry.Value);
}
}

// Create plain text alternative view
string baseTxtTemplate = File.ReadAllText(Path.Combine(fullTemplatePath, TXT_BASE_TEMPLATE));
textBody = baseTxtTemplate.Replace(TAG_CONTENT, textBody);
AlternateView textView = AlternateView.CreateAlternateViewFromString(textBody, new System.Net.Mime.ContentType("text/plain"));

// Create html alternative view
string baseHtmlTemplate = File.ReadAllText(Path.Combine(fullTemplatePath, HTML_BASE_TEMPLATE));
htmlBody = baseHtmlTemplate.Replace(TAG_CONTENT, htmlBody);
AlternateView htmlView = AlternateView.CreateAlternateViewFromString(htmlBody, new System.Net.Mime.ContentType("text/html"));
// Add any html linked resources
if (htmlLinkedResources != null)
{
htmlLinkedResources.ForEach(lr => htmlView.LinkedResources.Add(lr));
htmlLinkedResources.ForEach(lr => textView.LinkedResources.Add(lr));
}

// Add the two views (gmail will always display plain text version if its added last)
mailMessage.AlternateViews.Add(textView);
mailMessage.AlternateViews.Add(htmlView);

// Add any attachments
if (attachments != null)
{
attachments.ForEach(a => mailMessage.Attachments.Add(a));
}

// Send the email.
SmtpClient smtp = new SmtpClient();
smtp.Send(mailMessage);
}
catch (Exception ex)
{
throw new Exception(String.Format("Error sending email (to:{0}, replyto:{1})", String.Join(",", to), replyTo), ex);
}
}

Sending Images as inline Attachment within HTML Email template using Django

I found the answer to my question...!
The problem was not in the code as I was expecting, but in the image, I was trying to send an 'SVG' image in my email message which is not supported by many email clients even Gmail so that was the problem. The code is working fine with other formats.
You can get more about supported email formats here:

How can I embed SVG into HTML in an email, so that it's visible in most/all email browsers?



Related Topics



Leave a reply



Submit