Send an email on Jenkins pipeline failure
Asked Answered
O

6

47

How can I add to a Jenkins pipeline an old-style post-build task which sends email when the build fails? I cannot find "Post-build actions" in the GUI for a pipeline. I know that I can wrap the entire build script try/catch, however, this seems ugly when the build script is large and continues to send emails even when the job was aborted manually. I would like to achieve the same functionality as with the previous email-ext based post-build action.

try {
    // Do sth
} catch(e) {
    emailext body: '$DEFAULT_CONTENT', 
        recipientProviders: [
            [$class: 'CulpritsRecipientProvider'],
            [$class: 'DevelopersRecipientProvider'],
            [$class: 'RequesterRecipientProvider']
        ], 
        replyTo: '$DEFAULT_REPLYTO', 
        subject: '$DEFAULT_SUBJECT',
        to: '$DEFAULT_RECIPIENTS'
    throw err
}
Of answered 27/9, 2016 at 8:51 Comment(4)
What did you end up doing? I have a similar requirement and keep on getting surprised when it comes to Jenkins design. How is email alert something we may want to duplicated all around and within pipelines? are we really being suggested to mix code revisions with email notification settings - this makes no sense to me.Eyeleteer
@Eyeleteer i'm still using the emailext body... method above. Haven't found anything better and wasted enough time on this :)Of
Ok thanks, really not impressed with Jenkins!Eyeleteer
@Eyeleteer Pipilines in Jenkins are a hurried response to "guys, it's 201*, people are maintaining their configuration as code, let's do something so that they don't dump us".Springhouse
S
63

This answer worked on my Jenkins ver. 2.96.

Jenkins pipeline email not sent on build failure - Stack Overflow

 pipeline {  
     agent any  
     stages {  
         stage('Test') {  
             steps {  
                 sh 'echo "Fail!"; exit 1'  
             }  
         }  
     }  
     post {  
         always {  
             echo 'This will always run'  
         }  
         success {  
             echo 'This will run only if successful'  
         }  
         failure {  
             mail bcc: '', body: "<b>Example</b><br>Project: ${env.JOB_NAME} <br>Build Number: ${env.BUILD_NUMBER} <br> URL de build: ${env.BUILD_URL}", cc: '', charset: 'UTF-8', from: '', mimeType: 'text/html', replyTo: '', subject: "ERROR CI: Project name -> ${env.JOB_NAME}", to: "[email protected]";  
         }  
         unstable {  
             echo 'This will run only if the run was marked as unstable'  
         }  
         changed {  
             echo 'This will run only if the state of the Pipeline has changed'  
             echo 'For example, if the Pipeline was previously failing but is now successful'  
         }  
     }  
 }

Official documentation for the mail step

Streptococcus answered 19/12, 2017 at 7:51 Comment(7)
I had to remove the 2nd backslash in \n\ to get this to work.Homothermal
What is mail? Is it from a plugin? Is it different than emailext?Main
@Streptococcus how can I send only one email after failure and wait until the build will be successful? I don't want to send another email if the next build will be a failure.Arroba
mail is different than emailext - I'm still trying to find the documentation O_oObstreperous
I assume this works after setting up smtp credentials? I did that and was able to send a test email, it does not send from my pipeline.Swelter
@Obstreperous This is all I could find -> jenkins.io/doc/pipeline/steps/workflow-basic-steps/#mail-mailPisciform
@Arroba You can use the 'changed' post method, and check wether currentBuild.currentResult=="FAILURE" (with a script clause if you use declarative script)Overpower
K
29

For taking action only when build status has changed you can use the post > changed block.

And for checking, what state the status has changed to you can use the script block in combination with checking the value of currentBuild.currentResult property.

Like so:

pipeline {
    ...

    post {
        changed {
            script {
                if (currentBuild.currentResult == 'FAILURE') { // Other values: SUCCESS, UNSTABLE
                    // Send an email only if the build status has changed from green/unstable to red
                    emailext subject: '$DEFAULT_SUBJECT',
                        body: '$DEFAULT_CONTENT',
                        recipientProviders: [
                            [$class: 'CulpritsRecipientProvider'],
                            [$class: 'DevelopersRecipientProvider'],
                            [$class: 'RequesterRecipientProvider']
                        ], 
                        replyTo: '$DEFAULT_REPLYTO',
                        to: '$DEFAULT_RECIPIENTS'
                }
            }
        }
    }

}
Kinson answered 31/8, 2017 at 22:17 Comment(0)
S
19

At the moment you have to use this procedure with a try-catch to get a post-build action.

But in the future this step is planned (actually it is in review). You can read the blog post for further information (see the declarative pipeline part). See also the the Jenkins Jira ticket and the pull request.

Update:

The Jenkins declarative pipeline now has the post section that will run steps conditionally at the end of each build. See the docs for more information.

post {
 always {
   sh 'echo "This will always run"'
 }
 success {
  sh 'echo "This will run only if successful"'
 }
 failure {
  sh 'echo "This will run only if failed"'
 }
 unstable {
  sh 'echo "This will run only if the run was marked as unstable"'
 }
 changed {
  sh 'echo "This will run only if the state of the Pipeline has changed"'
  sh 'echo "For example, the Pipeline was previously failing but is now successful"'
  sh 'echo "... or the other way around :)"'
 }
}
Schapira answered 1/10, 2016 at 11:15 Comment(2)
@MariuszJamro they should. They could wrap existing scripting code in script blocks.Springhouse
@AbhijitSarkar Not necessarily - there are still some usecases where declarative won't do the trick - see the discussion here for instance: issues.jenkins-ci.org/browse/JENKINS-41335Merissameristem
B
12

This is working well on my Jenkins (current ver 2.164.2 and emailext) with declarative pipeline:

pipeline {
...

environment {
        EMAIL_TO = '[email protected]'
    }
post {
        failure {
            emailext body: 'Check console output at $BUILD_URL to view the results. \n\n ${CHANGES} \n\n -------------------------------------------------- \n${BUILD_LOG, maxLines=100, escapeHtml=false}', 
                    to: "${EMAIL_TO}", 
                    subject: 'Build failed in Jenkins: $PROJECT_NAME - #$BUILD_NUMBER'
        }
        unstable {
            emailext body: 'Check console output at $BUILD_URL to view the results. \n\n ${CHANGES} \n\n -------------------------------------------------- \n${BUILD_LOG, maxLines=100, escapeHtml=false}', 
                    to: "${EMAIL_TO}", 
                    subject: 'Unstable build in Jenkins: $PROJECT_NAME - #$BUILD_NUMBER'
        }
        changed {
            emailext body: 'Check console output at $BUILD_URL to view the results.', 
                    to: "${EMAIL_TO}", 
                    subject: 'Jenkins build is back to normal: $PROJECT_NAME - #$BUILD_NUMBER'
        }
    }
}

You can control email for failed build or changed status. Also I've put build log to the email body

Bismuthinite answered 11/4, 2019 at 16:56 Comment(0)
F
2

to DRY your scripted pipelines you can easily extend Jenkins with your own shared library and define a custom step emailOnError by creating vars/emailOnError.groovy with the following:

def call(Closure action) {
    try {
        action()
    } catch(e){
        emailext    body: '$DEFAULT_CONTENT', 
                    recipientProviders: [
                        [$class: 'DevelopersRecipientProvider'],
                        [$class: 'RequesterRecipientProvider']
                    ], 
                    replyTo: '$DEFAULT_REPLYTO', 
                    subject: '$PROJECT_NAME - Build # $BUILD_NUMBER - ERROR!',
                    to: '$DEFAULT_RECIPIENTS'
        throw err
    }   
}

Note that this shared method emailOnError comes from vars/emailOnError.groovy and can be used like this:

emailOnError() {
    // Do sth   
}
Forgive answered 24/6, 2020 at 8:52 Comment(0)
S
2

Almost all above answers are correct but this one I am using in post section when the build is failed. Maybe this can be useful

post {
always {
  script {
    if (currentBuild.currentResult == 'FAILURE') {
      step([$class: 'Mailer', notifyEveryUnstableBuild: true, recipients: "[email protected]", sendToIndividuals: true])
    }
  }
}
Shoebill answered 24/6, 2020 at 9:19 Comment(3)
There is a missing double quote "closing" the recipient value.Gurge
Done. Thanks @GurgeShoebill
can't you remove the "if" condition, if you switch to "failure" instead of "always"? I mean that's what they're for...Saphena

© 2022 - 2024 — McMap. All rights reserved.