Linux Mail < File.Log Has Content-Type: Application/Octet-Stream (A Noname Attachment in Gmail)

linux mail file.log has Content-Type: application/octet-stream (a noname attachment in Gmail)

The man page is a good place to start! Keep reading until you get to the MIME TYPES section, and pay close attention the following:

Otherwise, or if the filename has no extension, the content types
text/plain or application/octet-stream are
used, the first for text or international text files, the second for any file that contains formatting char‐
acters other than newlines and horizontal tabulators.

So, if your message contains "formatting characters" (which in general means control characters) other than newlines and tabs, it will automatically be classified as application/octet-stream. I bet that if you look closely at the data you'll find some control characters floating around.

You can work around this by...

  • Including the log file as an attachment (using -a) instead of the main message body, and set up your ~/.mime.types file to identify *.log files as text/plain.
  • Filter out control characters using something like tr.
  • Use another MUA such as mutt to send the mail. In fact, you could just craft a message yourself and send it directly to sendmail:

    (
    echo To: person@example.com
    echo From: you@example.com
    echo Subject: a logfile
    echo
    cat logfile.log
    ) | sendmail -t

Python Emailed PDF Arriving with no name

I think you should set the MIME type to application/pdf, not application/octet-stream.

Specify the filename like this:

 msg.add_header('Content-Disposition', 'attachment', filename=filename)

Is there a quick way to send email attachments in python using SMTP without knowing the file type in advance?

SMTP doesn't care what the attachment contains. Just put it as application/octet-stream and hope the recipient knows what to do with it. But make sure you spell the MIME type correctly. ("Octet" is just a fancy way to say "8-bit byte".)

Also, Content-Decomposition is not a valid MIME header name; you want Content-Disposition.

These horrible typos are probably why you observed problems in some clients. They can't guess what you mean when you misspell critical technical keywords.

More fundamentally, you appear to have copy/pasted email code from several years back for both of your attempts. The current Python 3.6+ email library code is much more readable and versatile. Probably throw away what you have and start over with the examples in the documentation.

If you can guess correctly the MIME type of the file you are transmitting, adding that information to the MIME headers would be useful; but automating this for arbitrary attachment types is unlikely to be helpful. If your guessing logic guesses wrong, you are just making things harder by claiming that you know when you don't.

So, I don't particularly recommend even trying; but if you want to verify for yourself that this is futile, try the mimetypes.guess_type method from the standard library. The documentation suggests that this just contains canned guesses for a collection of file name extensions; a more thorough approach would be to use the actual contents of the file and libmagic or similar to attempt to identify what it is.

Calling Linux's mailx through java code: message-text always goes into attachment

EDIT : Replaced stupid things by a correct solution

The mailx command found in the majority of Linux distribution is heirloom mailx. It does much more things than the original BSD mailx and automatically encodes its input if there are any non printable characters in it*.

The problem here is that it consideres that the \r characters are non standards and so it adds the following headers to the mail :

Content-Type: application/octet-stream
Content-Transfert-Encoding: base64

and the text of the mail is effectively base 64 encoded. It is not a true attachement, but many mail readers treat such mails as an empty body with an unnamed attached file.

So the solution is to remove all the \r from the body of the mail.

In fact, if your LANG environment variable declares a locale that can use non 7 bits chars (éèûôüö ...) mailx seems to be clever enough to declare an extended charset (ISO-8859-1 for fr locale) and to do quoted-printable encoding. So even with (at least west european) non 7bits ASCII characters in the message, provided there are no control chararacters, the mail should be sent normally.

The last chance solution would be not to use mailx and directly use sendmail.

Email attachment received as 'noname'

Your header isn't correct. filename is the attribute not a string.

# Add header to variable with attachment file
attach_file.add_header('Content-Disposition', 'attachment', filename=attachment)
# Then attach to message attachment file
message.attach(attach_file)

Mail multipart/alternative vs multipart/mixed

I hit this challenge today and I found these answers useful but not quite explicit enough for me.

Edit: Just found the Apache Commons Email that wraps this up nicely, meaning you don't need to know below.

If your requirement is an email with:

  1. text and html versions
  2. html version has embedded (inline) images
  3. attachments

The only structure I found that works with Gmail/Outlook/iPad is:

  • mixed

    • alternative

      • text
      • related

        • html
        • inline image
        • inline image
    • attachment
    • attachment

And the code is:

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.URLDataSource;
import javax.mail.BodyPart;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Created by StrongMan on 25/05/14.
*/
public class MailContentBuilder {

private static final Pattern COMPILED_PATTERN_SRC_URL_SINGLE = Pattern.compile("src='([^']*)'", Pattern.CASE_INSENSITIVE);
private static final Pattern COMPILED_PATTERN_SRC_URL_DOUBLE = Pattern.compile("src=\"([^\"]*)\"", Pattern.CASE_INSENSITIVE);

/**
* Build an email message.
*
* The HTML may reference the embedded image (messageHtmlInline) using the filename. Any path portion is ignored to make my life easier
* e.g. If you pass in the image C:\Temp\dog.jpg you can use <img src="dog.jpg"/> or <img src="C:\Temp\dog.jpg"/> and both will work
*
* @param messageText
* @param messageHtml
* @param messageHtmlInline
* @param attachments
* @return
* @throws MessagingException
*/
public Multipart build(String messageText, String messageHtml, List<URL> messageHtmlInline, List<URL> attachments) throws MessagingException {
final Multipart mpMixed = new MimeMultipart("mixed");
{
// alternative
final Multipart mpMixedAlternative = newChild(mpMixed, "alternative");
{
// Note: MUST RENDER HTML LAST otherwise iPad mail client only renders the last image and no email
addTextVersion(mpMixedAlternative,messageText);
addHtmlVersion(mpMixedAlternative,messageHtml, messageHtmlInline);
}
// attachments
addAttachments(mpMixed,attachments);
}

//msg.setText(message, "utf-8");
//msg.setContent(message,"text/html; charset=utf-8");
return mpMixed;
}

private Multipart newChild(Multipart parent, String alternative) throws MessagingException {
MimeMultipart child = new MimeMultipart(alternative);
final MimeBodyPart mbp = new MimeBodyPart();
parent.addBodyPart(mbp);
mbp.setContent(child);
return child;
}

private void addTextVersion(Multipart mpRelatedAlternative, String messageText) throws MessagingException {
final MimeBodyPart textPart = new MimeBodyPart();
textPart.setContent(messageText, "text/plain");
mpRelatedAlternative.addBodyPart(textPart);
}

private void addHtmlVersion(Multipart parent, String messageHtml, List<URL> embeded) throws MessagingException {
// HTML version
final Multipart mpRelated = newChild(parent,"related");

// Html
final MimeBodyPart htmlPart = new MimeBodyPart();
HashMap<String,String> cids = new HashMap<String, String>();
htmlPart.setContent(replaceUrlWithCids(messageHtml,cids), "text/html");
mpRelated.addBodyPart(htmlPart);

// Inline images
addImagesInline(mpRelated, embeded, cids);
}

private void addImagesInline(Multipart parent, List<URL> embeded, HashMap<String,String> cids) throws MessagingException {
if (embeded != null)
{
for (URL img : embeded)
{
final MimeBodyPart htmlPartImg = new MimeBodyPart();
DataSource htmlPartImgDs = new URLDataSource(img);
htmlPartImg.setDataHandler(new DataHandler(htmlPartImgDs));
String fileName = img.getFile();
fileName = getFileName(fileName);
String newFileName = cids.get(fileName);
boolean imageNotReferencedInHtml = newFileName == null;
if (imageNotReferencedInHtml) continue;
// Gmail requires the cid have <> around it
htmlPartImg.setHeader("Content-ID", "<"+newFileName+">");
htmlPartImg.setDisposition(BodyPart.INLINE);
parent.addBodyPart(htmlPartImg);
}
}
}

private void addAttachments(Multipart parent, List<URL> attachments) throws MessagingException {
if (attachments != null)
{
for (URL attachment : attachments)
{
final MimeBodyPart mbpAttachment = new MimeBodyPart();
DataSource htmlPartImgDs = new URLDataSource(attachment);
mbpAttachment.setDataHandler(new DataHandler(htmlPartImgDs));
String fileName = attachment.getFile();
fileName = getFileName(fileName);
mbpAttachment.setDisposition(BodyPart.ATTACHMENT);
mbpAttachment.setFileName(fileName);
parent.addBodyPart(mbpAttachment);
}
}
}

public String replaceUrlWithCids(String html, HashMap<String,String> cids)
{
html = replaceUrlWithCids(html, COMPILED_PATTERN_SRC_URL_SINGLE, "src='cid:@cid'", cids);
html = replaceUrlWithCids(html, COMPILED_PATTERN_SRC_URL_DOUBLE, "src=\"cid:@cid\"", cids);
return html;
}

private String replaceUrlWithCids(String html, Pattern pattern, String replacement, HashMap<String,String> cids) {
Matcher matcherCssUrl = pattern.matcher(html);
StringBuffer sb = new StringBuffer();
while (matcherCssUrl.find())
{
String fileName = matcherCssUrl.group(1);
// Disregarding file path, so don't clash your filenames!
fileName = getFileName(fileName);
// A cid must start with @ and be globally unique
String cid = "@" + UUID.randomUUID().toString() + "_" + fileName;
if (cids.containsKey(fileName))
cid = cids.get(fileName);
else
cids.put(fileName,cid);
matcherCssUrl.appendReplacement(sb,replacement.replace("@cid",cid));
}
matcherCssUrl.appendTail(sb);
html = sb.toString();
return html;
}

private String getFileName(String fileName) {
if (fileName.contains("/"))
fileName = fileName.substring(fileName.lastIndexOf("/")+1);
return fileName;
}
}

And an example of using it with from Gmail

/**
* Created by StrongMan on 25/05/14.
*/
import com.sun.mail.smtp.SMTPTransport;

import java.net.URL;
import java.security.Security;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.URLDataSource;
import javax.mail.*;
import javax.mail.internet.*;

/**
*
* http://stackoverflow.com/questions/14744197/best-practices-sending-javamail-mime-multipart-emails-and-gmail
* http://stackoverflow.com/questions/3902455/smtp-multipart-alternative-vs-multipart-mixed
*
*
*
* @author doraemon
*/
public class GoogleMail {


private GoogleMail() {
}

/**
* Send email using GMail SMTP server.
*
* @param username GMail username
* @param password GMail password
* @param recipientEmail TO recipient
* @param title title of the message
* @param messageText message to be sent
* @throws AddressException if the email address parse failed
* @throws MessagingException if the connection is dead or not in the connected state or if the message is not a MimeMessage
*/
public static void Send(final String username, final String password, String recipientEmail, String title, String messageText, String messageHtml, List<URL> messageHtmlInline, List<URL> attachments) throws AddressException, MessagingException {
GoogleMail.Send(username, password, recipientEmail, "", title, messageText, messageHtml, messageHtmlInline,attachments);
}

/**
* Send email using GMail SMTP server.
*
* @param username GMail username
* @param password GMail password
* @param recipientEmail TO recipient
* @param ccEmail CC recipient. Can be empty if there is no CC recipient
* @param title title of the message
* @param messageText message to be sent
* @throws AddressException if the email address parse failed
* @throws MessagingException if the connection is dead or not in the connected state or if the message is not a MimeMessage
*/
public static void Send(final String username, final String password, String recipientEmail, String ccEmail, String title, String messageText, String messageHtml, List<URL> messageHtmlInline, List<URL> attachments) throws AddressException, MessagingException {
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";

// Get a Properties object
Properties props = System.getProperties();
props.setProperty("mail.smtps.host", "smtp.gmail.com");
props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);
props.setProperty("mail.smtp.socketFactory.fallback", "false");
props.setProperty("mail.smtp.port", "465");
props.setProperty("mail.smtp.socketFactory.port", "465");
props.setProperty("mail.smtps.auth", "true");

/*
If set to false, the QUIT command is sent and the connection is immediately closed. If set
to true (the default), causes the transport to wait for the response to the QUIT command.

ref : http://java.sun.com/products/javamail/javadocs/com/sun/mail/smtp/package-summary.html
http://forum.java.sun.com/thread.jspa?threadID=5205249
smtpsend.java - demo program from javamail
*/
props.put("mail.smtps.quitwait", "false");

Session session = Session.getInstance(props, null);

// -- Create a new message --
final MimeMessage msg = new MimeMessage(session);

// -- Set the FROM and TO fields --
msg.setFrom(new InternetAddress(username + "@gmail.com"));
msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipientEmail, false));

if (ccEmail.length() > 0) {
msg.setRecipients(Message.RecipientType.CC, InternetAddress.parse(ccEmail, false));
}

msg.setSubject(title);

// mixed
MailContentBuilder mailContentBuilder = new MailContentBuilder();
final Multipart mpMixed = mailContentBuilder.build(messageText, messageHtml, messageHtmlInline, attachments);
msg.setContent(mpMixed);
msg.setSentDate(new Date());

SMTPTransport t = (SMTPTransport)session.getTransport("smtps");

t.connect("smtp.gmail.com", username, password);
t.sendMessage(msg, msg.getAllRecipients());
t.close();
}

}


Related Topics



Leave a reply



Submit