Email Builder - An easy way to create custom emails for your groovy scripts

Hello everyone!

In my first (and hopefully not the last) article here on The Community I'd like to share an easy way to construct and send custom emails from your Groovy scripts. Please keep in mind that Scriptrunner add-on is required for this. 

While browsing the various questions here on The Community I've noticed that alot of people are asking how to send a custom email from their scripts. Now we do know that Scriptrunner has a great built-in script for sending custom emails, and most of the time it works fine. Unfortunatly however you can't really use it from within your other scripts, which is especially the case if you store most of your scripts on file system. Nor does it allow you to set various parts of your email conditionally (like subject, body, attachments, recipients, etc).

With that in mind I've developed this rather simple class which allows you once imported into your other scripts to easily construct and send custom email. We've already had a similar builder for creating and updating issues, developed by my colleague and fellow champion @Mark Markov so I figured this logic could be used for emails as well. 

package ru.tovbin.ivan.builders

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.attachment.Attachment
import com.atlassian.jira.util.PathUtils
import com.atlassian.mail.Email
import com.atlassian.mail.server.SMTPMailServer
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import javax.activation.DataHandler
import javax.activation.FileDataSource
import javax.mail.BodyPart
import javax.mail.Multipart
import javax.mail.internet.MimeBodyPart
import javax.mail.internet.MimeMultipart
import com.atlassian.jira.issue.Issue

class EmailBuilder {

private static Logger log = LoggerFactory.getLogger(this.class.getName())
private Email email
private EmailBuilder(){}

public static Builder create(String to){
return new EmailBuilder.Builder(new EmailBuilder()).createEmail(new Email(to))
}

private static File getFilePath(Attachment attachment){
log.debug("Getting path for attachment ${attachment.getFilename()} from issue ${attachment.getIssue().getKey()}...")
int u = Integer.parseInt(attachment.getIssue().getKey().split("-")[1])
int kk = (int)Math.ceil(u/10000)*10000
String path = PathUtils.joinPaths(ComponentAccessor.getAttachmentPathManager().getAttachmentPath(), attachment.getIssue().getProjectObject().getKey(), kk.toString() ,attachment.getIssue().getKey(), attachment.getId().toString())
log.debug("File path for ${attachment.getFilename()}: ${path}")
File filePath = new File(path)
return filePath
}

private static BodyPart getAttachBody(File filePath, String fileName){
log.debug("Building body for file ${fileName} at path ${filePath.toString()}....")
BodyPart attachBody = new MimeBodyPart()
attachBody.setDataHandler(new DataHandler(new FileDataSource(filePath)))
log.debug("Body data handler name:${attachBody.getDataHandler().getName()}")
attachBody.setFileName(fileName)
log.debug("Body filename: ${attachBody.getFileName()}")
return attachBody

}

public class Builder {
private Builder() {}

private Builder createEmail(Email email){
EmailBuilder.this.email = email
return this
}

public Builder setFromName(String fromName){
log.debug("setFromName. value: {}", fromName)
EmailBuilder.this.email.setFromName(fromName)
return this
}

public Builder setFrom(String from){
log.debug("setFrom. value: {}", from)
EmailBuilder.this.email.setFrom(from)
return this
}

public Builder setTo(String to){
log.debug("setTo. value: {}", to)
EmailBuilder.this.email.setTo(to)
return this
}

public Builder setCc(String cc){
log.debug("setCc. value: {}", cc)
EmailBuilder.this.email.setCc(cc)
return this
}

public Builder setSubject(String subject){
log.debug("setSubject. value: {}", subject)
EmailBuilder.this.email.setSubject(subject)
return this
}

public Builder setBody(String body){
log.debug("setBody. value: {}", body)
EmailBuilder.this.email.setBody(body)
return this
}

public Builder setMimeType(String mimeType){
log.debug("setMimeType. value: {}", mimeType)
EmailBuilder.this.email.setMimeType(mimeType)
return this
}

public Builder addAttachments(List<Attachment> attachmentList){
log.debug("Attachments to add: ${attachmentList.toString()}")
Multipart multipart = new MimeMultipart()
for (int i = 0; i < attachmentList.size(); i++){
multipart.addBodyPart(EmailBuilder.getAttachBody(EmailBuilder.getFilePath(attachmentList[i]), attachmentList[i].getFilename()))
}
EmailBuilder.this.email.setMultipart(multipart)
return this
}

public EmailBuilder send() {
SMTPMailServer mailServer = ComponentAccessor.getMailServerManager().getDefaultSMTPMailServer()
Thread.currentThread().setContextClassLoader(javax.mail.Message.class.getClassLoader())
log.debug(EmailBuilder.this.email.toString())
mailServer.send(EmailBuilder.this.email)
return EmailBuilder.this;
}
}
}

 

And here's how you use it in your scripts:

import ru.tovbin.ivan.builders.EmailBuilder

EmailBuilder.create("destination@email.com")
.setFromName("some name")
.setFrom("from@email.com")
.setCc("copy@email.com")
.setSubject("some subject")
.setBody("some body")
.setMimeType("text/html")
.addAttachments(issue.getAttachments())
.send()

Pretty easy, huh?

Well that's about it, I hope this will be helpful. Please feel free to share your thoughts and questions. Any feedback is always welcome!

8 comments

Gonchik Tsymzhitov Community Champion Jan 17, 2019

Hi! 

 

Thanks for your article. 

Do you have experience with generating email in different formats like RTF, HTML ? 

And of course, how do you handling styles, footer and some scripts? Also, it will be so interesting how it represent in Office365, G-Suite, Yahoo and Zimbra. 

 

Thanks 

 

Cheers,

Gonchik Tsymzhitov

Ivan Tovbin Community Champion Jan 17, 2019

@Gonchik Tsymzhitov

We pass "text/html" to setMimeType() method and simply use HTML tags in email body, like so:

setBody("<font face=\"Calibri\" size=\"3\" color=\"black\"><b>some text:</b> <a href=\"$baseUrl/browse/$key\">ABC-123</a>some text<br><br><b>some text</b> some more text<br><b>some more text</b> some text<br><b>some tesxt</b></font>"
Gonchik Tsymzhitov Community Champion Jan 17, 2019

@Ivan Tovbin Thanks for your awesome clarify. 

BTW, have you check it on related platrforms? Or what kind of mail service or server do you using?

Ivan Tovbin Community Champion Jan 17, 2019

@Gonchik Tsymzhitov

We've been usuing IMB Notes 9 so far, but are looking at MS Exchange right now. Didn't really have any problems with either.

Gonchik Tsymzhitov Community Champion Jan 17, 2019

Thanks for opening my eyes about  IBM Notes 9 :)

@Ivan Tovbin How can you here generate valid urls to jira tickets and other objects from java-objects in code? :)

 

For example - you need to mention $issue and username. How can I do it with this class? 

Ivan Tovbin Community Champion Jan 17, 2019

@Evgeniy Buturlia

I suppose something like this should do the trick:

import com.atlassian.jira.component.ComponentAccessor

String baseurl = ComponentAccessor.getApplicationProperties().getString("jira.baseurl")
String issueUrl = "${baseurl}/browse/${issue.getKey()}"

Useful, thanks

Comment

Log in or Sign up to comment
Community showcase
Published Wednesday in Jira

Make your Atlassian Cloud products more secure: our NEW admin security guide

Hey admins! I’m Dave, Principal Product Manager here at Atlassian working on our cloud platform and security products. Cloud security is a moving target. As you adopt more products, employees consta...

147 views 0 6
Read article

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you