Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in
Celebration

Earn badges and make progress

You're on your way to the next level! Join the Kudos program to earn points and save your progress.

Deleted user Avatar
Deleted user

Level 1: Seed

25 / 150 points

Next: Root

Avatar

1 badge earned

Collect

Participate in fun challenges

Challenges come and go, but your rewards stay with you. Do more to earn more!

Challenges
Coins

Gift kudos to your peers

What goes around comes around! Share the love by gifting kudos to your peers.

Recognition
Ribbon

Rise up in the ranks

Keep earning points to reach the top of the leaderboard. It resets every quarter so you always have a chance!

Leaderboard

Come for the products,
stay for the community

The Atlassian Community can help you and your team get more value out of Atlassian products and practices.

Atlassian Community about banner
4,456,656
Community Members
 
Community Events
176
Community Groups

How trigger custom email with PDF file attached base on user field update?

We have a Human Resource Jira project with multiple components, one is "New Hire". There is also a custom user field "User Account", once the hiring process is completed someone adds the new hire user id in that field and adds the start date.

We would like to send a custom email with a PDF file about the onboarding to the new hires once the user account field gets completed. At the same time would like to send another email to the Helpdesk to let them know what day new employees join and what technology need for them.

The logic is if the component value is "New Hire", the issue is unresolved and the "User Account" field is not empty then trigger an email to that user who mentioned in the user account field also send a separate email to the helpdesk and include new employee start date

How can trigger an email with a pdf attachment when the user account field gets updated?

1 answer

1 accepted

1 vote
Answer accepted

Hi @Shah Baloch

You could try using ScriptRunner's Listener and use the Custom Listener option for your requirement.

custom_listener.png

 

Below is a sample code for your reference:-

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.mail.Email
import com.atlassian.jira.user.ApplicationUser
import groovy.xml.MarkupBuilder
import org.apache.commons.io.FileUtils

import javax.mail.internet.MimeBodyPart
import javax.mail.internet.MimeMultipart

def issue = event.issue

def customFieldManager = ComponentAccessor.customFieldManager
def attachmentManager = ComponentAccessor.attachmentManager

def userPicker = customFieldManager.getCustomFieldObjectsByName('User Account').first()
def userPickerValue = issue.getCustomFieldValue(userPicker) as ApplicationUser
def attachments = attachmentManager.getAttachments(issue)

final def jiraResourcesPath = '/media/ram/Linux_Disk_Space/atlassian/application-data/jira8/data/attachments'
final def project = issue.projectObject
final def projectKey = project.key
final def issueKey = issue.key
final def recipientEmail = userPickerValue.emailAddress
final def destinationPath = '/tmp'
final def subject = 'This is a test mail'

def emailBody = new StringWriter()
def html = new MarkupBuilder(emailBody)

html.html {
body {
h1 'New Employee'
h2 'Sample Content For Testing Purposes'
}
}

def latestAttachment = attachments.findAll {
it.filename.endsWith('.pdf')
}.sort { it.created }.last()


def fileName = latestAttachment.id
def filePath = "${jiraResourcesPath}/${projectKey}/10000/${issueKey}".toString()
def oldFile = new File("${filePath}/${fileName}")
def dest = new File("${destinationPath}/${userPickerValue.displayName}.pdf")
FileUtils.copyFile(oldFile, dest)
creatMessage(recipientEmail, subject, emailBody.toString(), "${dest.canonicalPath}")
FileUtils.forceDelete(dest)


static creatMessage(String to, String subject, String content, String filename) {
def mailServerManager = ComponentAccessor.mailServerManager
def mailServer = mailServerManager.defaultSMTPMailServer

def multipart = new MimeMultipart()
def body = new MimeBodyPart()
def mailAttachment = new MimeBodyPart()

body.setContent(content, 'text/html; charset=utf-8')
mailAttachment.attachFile(new File(filename))

multipart.addBodyPart(body)
multipart.addBodyPart(mailAttachment)

def email = new Email(to)
email.setSubject(subject)
email.setMultipart(multipart)
email.setMimeType("text/html")

def threadClassLoader = Thread.currentThread().contextClassLoader
Thread.currentThread().contextClassLoader = mailServer.class.classLoader
mailServer.send(email)
Thread.currentThread().contextClassLoader = threadClassLoader
}

Please note the working sample code above is not 100% exact to your environment. Hence, you will need to make the required modifications.

Below is a print screen of the Listener configuration:-

listener_config.png

If you observe in the print screen, the set event is the Issue Created event. Hence, when the Issue is created and the pdf attachment is added, it will be added to the email and the pdf file is renamed to the recipient's name.

Below is an example email output for your reference:-

result.png

 

I hope this helps to solve your question. :)

 

Thank you and Kind Regards,

Ram

Thank you @Ram Kumar Aravindakshan _Adaptavist_ I tried your script, but it didn't send an email to the user mentioned in the "User Account" field. I saw an error in the log. Any idea why I'm getting errors?

2022-01-21 09:58:22,339 ERROR [runner.AbstractScriptListener]: ************************************************************************************* 2022-01-21 09:58:22,347 ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: null java.util.NoSuchElementException: Cannot access last() element from an empty List at Script267.run(Script267.groovy:37)

and

2022-01-21 12:03:40,200 ERROR [runner.AbstractScriptListener]: ************************************************************************************* 2022-01-21 12:03:40,200 ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: null java.lang.NullPointerException: Cannot get property 'emailAddress' on null object at Script267.run(Script267.groovy:23)

 

Thank you

Hi @Shah Baloch

As mentioned in my comment:-

Please note the working sample code above is not 100% exact to your environment. Hence, you will need to make the required modifications. 

You will need to modify the names of the fields that you are using according to your environment.

The main parameters that you will need to modify are:-

def userPicker = customFieldManager.getCustomFieldObjectsByName('User Account').first()
...
final def jiraResourcesPath = '/media/ram/Linux_Disk_Space/atlassian/application-data/jira8/data/attachments'
...
final def
destinationPath = '/tmp'
...
final def
subject = 'This is a test mail'

For the user picker, i.e. userPicker, you will need to update the field's name according to your environment.

For the jiraResourcePath, you will need to modify the path according to your environment.

Also, for the destinationPath, you will need to modify the path where you want to copy the file to.

Could you please share a print screen of your Create screen and include the user picker you are using?

If you have not made any changes to the code, the error appears to be coming from this line.

def latestAttachment = attachments.findAll {
it.filename.endsWith('.pdf')
}.sort { it.created }.last()

Could you please check if you have added the attachment to the ticket when you are creating the ticket?

Thank you and Kind Regards,

Ram

Like Shah Baloch likes this

@Ram Kumar Aravindakshan _Adaptavist_thank you. I forgot to update "JiraResourcePath". I updated the path and it worked.

Is there a way to keep a generic pdf file in the source location and get attached to the email whenever a user gets added in the "User Account" field? I mean attaching files to every issue will cause space issues in the future, also it issues creator can forget to attach the file.

For example, I copy the NewHire.pdf file to the attachment source location, and once the user field gets updated and the file should get attached with the email that sends to a new hire.

Thank you for your help.

Hi @Shah Baloch

Can you please confirm that you only want to add the pdf file from a fixed location and not include it in the issue's attachment?

If so, you will need to modify the code to:-

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.mail.Email
import com.atlassian.jira.user.ApplicationUser
import groovy.xml.MarkupBuilder
import org.apache.commons.io.FileUtils

import javax.mail.internet.MimeBodyPart
import javax.mail.internet.MimeMultipart

def issue = event.issue

def customFieldManager = ComponentAccessor.customFieldManager

def userPicker = customFieldManager.getCustomFieldObjectsByName('User Account').first()
def userPickerValue = issue.getCustomFieldValue(userPicker) as ApplicationUser

final def recipientEmail = userPickerValue.emailAddress
final def destinationPath = '/tmp' // Folder where template is stored
final def originalFileName = 'output.pdf' // Original pdf file name
final def subject = 'This is a test mail'

def emailBody = new StringWriter()
def html = new MarkupBuilder(emailBody)

html.html {
body {
h1 'New Employee'
h2 'Sample Content For Testing Purposes'
}
}
def oldFile = new File("${destinationPath}/${originalFileName}")
def dest = new File("${destinationPath}/${userPickerValue.displayName}.pdf") //File renamed according to name of user from user picker
FileUtils.copyFile(oldFile, dest)
creatMessage(recipientEmail, subject, emailBody.toString(), "${dest.canonicalPath}")


static creatMessage(String to, String subject, String content, String filename) {
def mailServerManager = ComponentAccessor.mailServerManager
def mailServer = mailServerManager.defaultSMTPMailServer

def multipart = new MimeMultipart()
def body = new MimeBodyPart()
def mailAttachment = new MimeBodyPart()

body.setContent(content, 'text/html; charset=utf-8')
mailAttachment.attachFile(new File(filename))

multipart.addBodyPart(body)
multipart.addBodyPart(mailAttachment)

def email = new Email(to)
email.setSubject(subject)
email.setMultipart(multipart)
email.setMimeType("text/html")

def threadClassLoader = Thread.currentThread().contextClassLoader
Thread.currentThread().contextClassLoader = mailServer.class.classLoader
mailServer.send(email)
Thread.currentThread().contextClassLoader = threadClassLoader
}
dest.delete() // delete modified file

You will need to modify the destination path and the original file name.

final def destinationPath = '/tmp' // Folder where pdf is stored
final def originalFileName = 'output.pdf' // Original pdf file name

Now, once the email is sent out, the original file will still be retained in the folder; only the newly modified file, i.e. which is renamed to the receiver's name, will be deleted.

I hope this helps to solve your question. :)

Thank you and Kind Regards,

Ram

Like Shah Baloch likes this

Hi @Ram Kumar Aravindakshan _Adaptavist_ It worked I can attach the same file all the time just rename it with the user's name. That's what we were looking for.

There is a couple of things we struggling with. We would like to add the user's name in the email body like "Hi XYZ". Also, we would like to include the hiring date. There is the field "Start date". We would like to add both.

I tried something like this but didn't work.

def startDate = customFieldManager.getCustomFieldObjectByName("Start date")

html.html {
body {
h1 'Hi ${userPickerValue.displayName}'
h2 'Welcome to our company, your start date in company is ${startDate.value} '
}
}

 

How it didn't work, it is displaying the code, but not the value.

How can I add the name and date in the email?

 

Thank you for your help.

Hi @Shah Baloch

When you want to append a variable in a String, in Groovy, you will need to use a double quote, i.e. " " instead of a single quote, i.e. ' '.

So, it should be something like this:-

html.html {
body {
h1 "New Employee ${userPickerValue.displayName}"
h2 "Welcome to our company, your start date in company is ${dateFormat.format(startDateValue)}"
}
}

Also, please note the getCustomFieldObjectByName method you have used to  invoke the custom field, i.e.

def startDate = customFieldManager.getCustomFieldObjectByName("Start date")

has been deprecated. You should instead use the getCustomFieldObjectsByName method as shown below:-

def startDate = customFieldManager.getCustomFieldObjectsByName("Start Date").first()

Below is the complete updated working sample code for your reference:-

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.mail.Email
import com.atlassian.jira.user.ApplicationUser
import groovy.xml.MarkupBuilder
import org.apache.commons.io.FileUtils

import javax.mail.internet.MimeBodyPart
import javax.mail.internet.MimeMultipart
import java.text.SimpleDateFormat

def issue = event.issue

def customFieldManager = ComponentAccessor.customFieldManager

def userPicker = customFieldManager.getCustomFieldObjectsByName('User Account').first()
def userPickerValue = issue.getCustomFieldValue(userPicker) as ApplicationUser

def startDate = customFieldManager.getCustomFieldObjectsByName("Start Date").first()
def startDateValue = issue.getCustomFieldValue(startDate) as Date
def dateFormat = new SimpleDateFormat('yyyy-MM-dd')

final def recipientEmail = userPickerValue.emailAddress
final def destinationPath = '/tmp' // Folder where template is stored
final def originalFileName = 'output.pdf' // Original Template
final def subject = 'This is a test mail'

def emailBody = new StringWriter()
def html = new MarkupBuilder(emailBody)

html.html {
body {
h1 "New Employee ${userPickerValue.displayName}"
h2 "Welcome to our company, your start date in company is ${dateFormat.format(startDateValue)}"
}
}
def oldFile = new File("${destinationPath}/${originalFileName}")
def dest = new File("${destinationPath}/${userPickerValue.displayName}.pdf") //File renamed according to name of user from user picker
FileUtils.copyFile(oldFile, dest)
creatMessage(recipientEmail, subject, emailBody.toString(), "${dest.canonicalPath}")

static creatMessage(String to, String subject, String content, String filename) {
def mailServerManager = ComponentAccessor.mailServerManager
def mailServer = mailServerManager.defaultSMTPMailServer

def multipart = new MimeMultipart()
def body = new MimeBodyPart()
def mailAttachment = new MimeBodyPart()

body.setContent(content, 'text/html; charset=utf-8')
mailAttachment.attachFile(new File(filename))

multipart.addBodyPart(body)
multipart.addBodyPart(mailAttachment)

def email = new Email(to)
email.setSubject(subject)
email.setMultipart(multipart)
email.setMimeType("text/html")

def threadClassLoader = Thread.currentThread().contextClassLoader
Thread.currentThread().contextClassLoader = mailServer.class.classLoader
mailServer.send(email)
Thread.currentThread().contextClassLoader = threadClassLoader
}
dest.delete() // delete modified file

Please note the working sample code above is not 100% exact to your environment. Hence, you will need to make the required modifications.

I hope this helps to answer your question. :)

Please don't forget to accept the answer as well.

Thank you and Kind regards,

Ram 

Hi, @Ram Kumar Aravindakshan _Adaptavist_ I just found out that the email should go to the user's personal email, not to work, because once they get hire they don't have access to the work email. Is there a way we can send the email to an external user? For example, instead of the "User Account" field, if we use a custom "Email Address" field where a value will be something like "test@gamil.com". I mean any email entered in the "Email Address" field the email should go to that email address. Is it possible to send an email to a user who doesn't have an account in Jira yet?

 

Also is there a way to change the email body's text into regular text?  Currently, the text is bold? I changed h1, h2 to h5 but still, it is making text bold.

 

I appreciate your help.

Hi @Shah Baloch

Sorry for the late reply; I was pretty busy.

I need to confirm with you, now that you want to use a custom email field, is there any need for the user picker field? Will you require it to invoke other user details?

Thank you and Kind Regards,

Ram

Hi, @Ram Kumar Aravindakshan _Adaptavist_ I was asking if there is a way to use a custom email field instead of a user picker field. The user picker field just picks up a user who has an account with us in Jira, but we are looking to send an email to an external user who doesn't have an account with us. For example, before someone officially joins our company they won't have access to any of the company accounts. We would like to send a pdf attachment to their personal email address, like ram@gamil.com. If that's something is possible.

Thank you for your help.

Hi @Shah Baloch

Thank you for the clarification.

So in your case, since the User Picker is not applicable, it can be removed from the code.

However, if you intend the PDF file to be named according to the Recipient's name, you will need to use a text field or something.

Also, if you intend to change the text type for the email, you can change it from Heading, i.e. h1, to Paragraph, i.e. p. For more information on the parameters that can be used, please visit this link.

Below is an updated sample code for your reference:-

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.mail.Email
import groovy.xml.MarkupBuilder
import org.apache.commons.io.FileUtils
import javax.mail.internet.MimeBodyPart
import javax.mail.internet.MimeMultipart
import java.text.SimpleDateFormat

def issue = event.issue

def customFieldManager = ComponentAccessor.customFieldManager

def startDate = customFieldManager.getCustomFieldObjectsByName("Start Date").first()
def startDateValue = issue.getCustomFieldValue(startDate) as Date
def dateFormat = new SimpleDateFormat('yyyy-MM-dd')

def newUserName = customFieldManager.getCustomFieldObjectsByName('New User Name').first()
def userUserNameValue = issue.getCustomFieldValue(newUserName) as String

def userEmail = customFieldManager.getCustomFieldObjectsByName('Sample Email').first()

final def recipientEmail = userEmail.getValue(issue).toString()
final def destinationPath = '/tmp' // Folder where template is stored
final def originalFileName = 'output.pdf' // Original Template
final def subject = 'This is a test mail'

def emailBody = new StringWriter()
def html = new MarkupBuilder(emailBody)

html.html {
body {
p "New Employee ${userUserNameValue}"
p "Welcome to our company, your start date in company is ${dateFormat.format(startDateValue)}"
}
}
def oldFile = new File("${destinationPath}/${originalFileName}")
def dest = new File("${destinationPath}/${userUserNameValue}.pdf") //File renamed according to name of user from user picker
FileUtils.copyFile(oldFile, dest)

creatMessage(recipientEmail, subject, emailBody.toString(), "${dest.canonicalPath}")

static creatMessage(String to, String subject, String content, String filename) {
def mailServerManager = ComponentAccessor.mailServerManager
def mailServer = mailServerManager.defaultSMTPMailServer

def multipart = new MimeMultipart()
def body = new MimeBodyPart()
def mailAttachment = new MimeBodyPart()

body.setContent(content, 'text/html; charset=utf-8')
mailAttachment.attachFile(new File(filename))

multipart.addBodyPart(body)
multipart.addBodyPart(mailAttachment)

def email = new Email(to)
email.setSubject(subject)
email.setMultipart(multipart)
email.setMimeType('text/html')

def threadClassLoader = Thread.currentThread().contextClassLoader
Thread.currentThread().contextClassLoader = mailServer.class.classLoader
mailServer.send(email)
Thread.currentThread().contextClassLoader = threadClassLoader
}
dest.delete() // delete modified file

 Below is a print screen of the Create Screen.email_sample.png

I hope this helps to answer your question. :)

Thank you and Kind Regards,

Ram

Like Shah Baloch likes this

Hi @Ram Kumar Aravindakshan _Adaptavist_, hi @Shah Baloch

I'v read this post with much interest, as this covers exactly my actual task.

But - may I ask you for an advice, as I run into errors all the time using the script as suggested finally in this post?

In our onboarding-Workflow, we'd like to send an static PDF with VPN-rules to the respective issue's reporter once the issue reaches a certain status.

But I fail selecting the correct sendto-address using the userpicker function in the code snippet if I select "reporter" as the respective user:

def userPicker = customFieldManager.getCustomFieldObjectsByName('Reporter').first()
def userPickerValue = issue.getCustomFieldValue(userPicker) as ApplicationUser

This leads to this error:

Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: null
java.util.NoSuchElementException: Cannot access first() element from an empty List
 at Script28.run(Script28.groovy:14)

 

So I changed the script to the last version suggested in these post and use a  customfield containing the reporter's email-Adress (UPN) but get the next error:

def userEmail = customFieldManager.getCustomFieldObjectsByName('UPN').first()

Error:

ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: null
java.util.NoSuchElementException: Cannot access first() element from an empty List
 at Script61.run(Script61.groovy:13)

 

I'm a bit lost here...

 

Thanks and best regards,

Erik

@Shah Baloch

@Ram Kumar Aravindakshan _Adaptavist_ ,

 

my apologies - like Murphy's law: once I sent my request to you, I found the error and was able to run the script as I hoped for.

 

Nonetheless - thanks for your previous discussion which helped me "on my way".

 

Best regards,
Erik

Like Shah Baloch likes this

Suggest an answer

Log in or Sign up to answer
TAGS

Atlassian Community Events