Sap
Sap

Reputation: 5291

Send multiple attachments with Grails Async Mail Plugin

I am using grails Async Mail plugin to send emails with attachments in my app. to achieve that I have written following code

def sendEmail = {
    def documentsInstances = Documents.getAll(params.list('ids[]'))
    def s3Service = new AmazonS3Service()
    documentsInstances.each(){documentsInstance->
            asyncMailService.sendMail {
                multipart true
                to documentsInstance.author.emailAddress
                subject 'Test';
                html '<body><u>Test</u></body>';
                attachBytes documentsInstance.filename , 'text/plain', s3Service.getBytes(session.uid,documentsInstance.filename);
            }
    }//

}

Now the code above works pretty much correctly but it sends an email per attachment, I am not sure how can I move this loop inside send mail so that I can send multiple attachments in an email.

Also is there a way to send an email so that I don't have to load a whole file in byte[]?

I am using JetS3t for access to Amazon S3 and I tried "attach" method with

new InputStreamResource(s3Obj.getDataInputStream()) ie

attach documentsInstance.filename , 'text/plain', new InputStreamResource(s3Obj.getDataInputStream());

but I am getting

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

Upvotes: 3

Views: 3448

Answers (1)

OverZealous
OverZealous

Reputation: 39570

You need your loop inside the email:

def sendEmail = {
    def documentsInstances = Documents.getAll(params.list('ids[]'))
    def s3Service = new AmazonS3Service()
    asyncMailService.sendMail {
        multipart true
        to documentsInstance.author.emailAddress
        subject 'Test';
        html '<body><u>Test</u></body>';

        // loop over attachments
        documentsInstances.each{ documentsInstance->
            attachBytes documentsInstance.filename , 'text/plain', s3Service.getBytes(session.uid, documentsInstance.filename);
        }
    }
}

This should attach multiple files.

If it throws an error about not being able to find an attachBytes method, you might need to explicitly call owner.attachBytes instead, which should refer to the outer sendMail closure.


Update based on comments:

The Async plugin looks like it defers to the normal mail plugin. The normal mail plugin's docs describes how to use multiple attachments.

This would look something like:

   // loop over attachments
    documentsInstances.each{ documentsInstance->
        attach documentsInstance.filename , 'text/plain', s3Service.getBytes(session.uid, documentsInstance.filename);
      //^^^^^^ Notice, just 'attach', not 'attachBytes'
    }

I don't know the S3 plugin you are using, but if there is a way to retrieve an InputStreamSource from it, it appears that you can stream the bytes directly to the mail plugin, instead of loading them into memory.

Upvotes: 3

Related Questions