43

The situation is like this:

First, we generate a file in the memory, we can get a InputStream object. Second the InputStream object must be send as a attachment of a email. The language is Java, we use Spring to send email.

I have found a lot of information, but I cannot find how to send an email attachment using InputStream. I try to do like this:

InputStreamSource iss= new InputStreamResource(new FileInputStream("c:\\a.txt"));
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true, "UTF-8");
message.addAttachment("attachment", iss);

But I get an exception:

Passed-in Resource contains an open stream: invalid argument. JavaMail requires an InputStreamSource that creates a fresh stream for every call.

informatik01
  • 16,038
  • 10
  • 74
  • 104
kaka2008
  • 693
  • 2
  • 8
  • 15
  • did you manage to do this? I've got the same problem. It doesn't quite make sense as the InputStreamResource is new and haven't been used before, not sure why Spring throws that exception?! – Stef May 13 '13 at 00:33
  • @Stef did you manage to do this? What I've managed til now it using a ByteArrayOutputStream and than: message.addAttachment(fileName, new ByteArrayResource(byteArrayOutputStream.toByteArray())); But for some reason it works when run as dev profile on the ide and not when build & run as java -jar target/projectName.jar. I get a com.sun.mail.smtp.SMTPSenderFailedException: 550 Request failed; Mailbox unavailable – Edmond Mar 13 '18 at 22:57
  • Sorry Edmond, I don't remember. I must have I guess, but don't even remember in what project this was :) – Stef Mar 21 '18 at 19:46
  • InputStreamResource implementation always returns true on method isOpen(). that is the problem. – fdm Nov 30 '18 at 13:43

5 Answers5

71

For files generated in memory, you may use ByteArrayResource. Just convert your InputStream object using IOUtils from the Apache Commons IO library.

It is quite simple:

helper.addAttachment("attachement",
new ByteArrayResource(IOUtils.toByteArray(inputStream)));
informatik01
  • 16,038
  • 10
  • 74
  • 104
ptr07
  • 746
  • 5
  • 6
  • 1
    Thank you. Works perfectly. – Kefirchiks Jun 09 '17 at 14:33
  • This can also be done without a library using the following: helper.addAttachment(ATTACHMENT_FILE_NAME, new ByteArrayResource(attachmentContent.getBytes(StandardCharsets.UTF_8)), MediaType.TEXT_HTML.toString()); – Scala Enthusiast Jun 12 '18 at 15:40
  • since attachment is converted to byte[], is there a way that we can attach a file with size is bigger than 2GB? – ktcl Aug 05 '20 at 11:47
7

Have a look at the spring reference chapter 24.3 Using the JavaMail MimeMessageHelper

The example is from there, I think it do want you want to do:

JavaMailSenderImpl sender = new JavaMailSenderImpl();
sender.setHost("mail.host.com");

MimeMessage message = sender.createMimeMessage();

// use the true flag to indicate you need a multipart message
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo("test@host.com");

helper.setText("Check out this image!");

// let's attach the infamous windows Sample file (this time copied to c:/)
FileSystemResource resource = new FileSystemResource(new File("c:/Sample.jpg"));

helper.addAttachment("CoolImage.jpg", resource );

sender.send(message);

if you want to use a Stream, then you can use

ByteArrayResource resource = new ByteArrayResource(IOUtils.toByteArray(inputStream)));

instead of FileSystemResource

Ralph
  • 118,862
  • 56
  • 287
  • 383
  • 1
    yeah,i know this. what i wanna know is how to send attachment with a InputStream Object rather than a file. because i generate a file in the memory , i don't want to save it on the disk. – kaka2008 Apr 16 '11 at 04:13
2

You can make simple implementation of InputStreamSource and pass fresh InputStream in it, as requested:

InputStreamSource iss = new InputStreamSource() {
    @Override
    public InputStream getInputStream() throws IOException {
        // provide fresh InputStream
        return new FileInputStream("c:\\a.txt");
    }
}
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true, "UTF-8");
message.addAttachment("attachment", iss);
Michal Moravcik
  • 2,250
  • 20
  • 18
1

The working examples are:

1) Attachment is an InputStreamSource interface

public void send() throws IOException, MessagingException {
    final ByteArrayOutputStream stream = createInMemoryDocument("body");
    final InputStreamSource attachment = new ByteArrayResource(stream.toByteArray());
    final MimeMessage message = javaMailSender.createMimeMessage();
    final MimeMessageHelper helper = new MimeMessageHelper(message, true);
    helper.setSubject("subject");
    helper.setFrom("from@from.com");
    helper.setTo("to@to.com");
    helper.setReplyTo("replyTo@replyTo.com");
    helper.setText("stub", false);
    helper.addAttachment("document.txt", attachment);
    javaMailSender.send(message);
}

2) Attachment is an DataSource interface

public void send() throws IOException, MessagingException {
        final ByteArrayOutputStream document = createInMemoryDocument("body");
        final InputStream inputStream = new ByteArrayInputStream(document.toByteArray());
        final DataSource attachment = new ByteArrayDataSource(inputStream, "application/octet-stream");
        final MimeMessage message = javaMailSender.createMimeMessage();
        final MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setSubject("subject");
        helper.setFrom("from@from.com");
        helper.setTo("to@to.com");
        helper.setReplyTo("replyTo@replyTo.com");
        helper.setText("stub", false);
        helper.addAttachment("document.txt", attachment);
        javaMailSender.send(message);
    }

The explanation:

Passed-in Resource contains an open stream: invalid argument. JavaMail requires an InputStreamSource that creates a fresh stream for every call.

This message could appear if the developer use an implementation of InputStreamSource that return true in the isOpen() method.

There is a special check in the method MimeMessageHelper#addAttacment():

public void addAttachment(String attachmentFilename, InputStreamSource inputStreamSource, String contentType) {
    //...
    if (inputStreamSource instanceof Resource && ((Resource) inputStreamSource).isOpen()) {
        throw new IllegalArgumentException(
        "Passed-in Resource contains an open stream: invalid argument. " +
        "JavaMail requires an InputStreamSource that creates a fresh stream for every call.");
    }
    //...
}

InputStreamResource#isOpen() always return true that makes impossible to use this implementation as an attachment:

public class InputStreamResource extends AbstractResource {
   //...
   @Override
   public boolean isOpen() {
      return true;
   }
   //...
}
Sergey Chepurnov
  • 1,397
  • 14
  • 23
0

//inlineFileObjectCreated -- you can create a StringBuilder Object for a example

ByteArrayDataSource source = new ByteArrayDataSource("file name", "contentType", inlineFileObjectCreated.getBytes() );

                JavaMailSender mailSender = (JavaMailSender) ServicesHome.getService("javaMailSender");
                MimeMessage mimeMessage = mailSender.createMimeMessage();
                MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
                mimeMessageHelper.setTo(toArray);           
                mimeMessageHelper.setSubject("");
                mimeMessageHelper.setText("");
                mimeMessageHelper.addAttachment("filename", source);
                mailSender.send(mimeMessageHelper.getMimeMessage());

/////////////////////////////////////////////

import javax.activation.DataSource;

    public class ByteArrayDataSource implements DataSource {
        byte[] bytes;
        String contentType;
        String name;

        public ByteArrayDataSource( String name, String contentType, byte[] bytes ) {
          this.name = name;
          this.bytes = bytes;
          this.contentType = contentType;
        }

        public String getContentType() {
          return contentType;
        }

        public InputStream getInputStream() {
          return new ByteArrayInputStream(bytes);
        }

        public String getName() {
          return name;
        }

        public OutputStream getOutputStream() throws IOException {
          throw new FileNotFoundException();
        }
      }
Sujith
  • 141
  • 2
  • 14