It's not the same without you

Join the community to find out what other Atlassian users are discussing, debating and creating.

Atlassian Community Hero Image Collage

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

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 Leader 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>"

@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 Leader 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.

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 Leader Jan 17, 2019

@Евгений Бутурля

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
Posted in Jira

We want to hear from you! How do you use Slack and Atlassian together?

Hi Everyone! My name is Mina and I am on Atlassian’s Ecosystems Marketing team. Our team is focused on our technology partnerships and marketplace apps. One of Atlassian’s partners is Slack, who ...

99 views 1 6
Join discussion

Community Events

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

Find an event

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

Unfortunately there are no Community Events near you at the moment.

Host an event

You're one step closer to meeting fellow Atlassian users at your local event. Learn more about Community Events

Events near you