Home DevOps Jenkins Email Notification: SMTP Setup, Templates & Production Debugging
Intermediate ✅ Tested on Jenkins 2.440+ | Email Extension Plugin 2.0+ 10 min · 2026-07-09

Jenkins Email Notification: SMTP Setup, Templates & Production Debugging

Learn production-grade Jenkins email notification setup: SMTP config for Gmail/SendGrid/internal, Email Extension vs built-in mailer, token templates, attachment patterns, per-trigger config, and troubleshooting delivery failures..

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Written from production experience, not tutorials.

Follow
Production
production tested
July 09, 2026
last updated
230
articles · all by Naren
Before you start⏱ 25 min
  • Solid grasp of devops fundamentals
  • Comfortable reading and writing code examples independently
  • Basic understanding of production deployment concepts
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • Use the Email Extension Plugin (2.100+) for per-trigger templates and Groovy scripting; avoid the built-in mailer for complex pipelines.
  • For Gmail SMTP (smtp.gmail.com:587), generate an App Password from your Google Account (Security > 2-Step Verification > App Passwords) and use that as the password.
  • SendGrid SMTP: server=smtp.sendgrid.net, port=587, username=apikey, password=your SendGrid API key.
  • Internal SMTP (e.g., Postfix): set Jenkins URL in 'Manage Jenkins > Configure System' under 'Jenkins Location' — many delivery failures trace back to a misconfigured Jenkins URL.
  • Use Extended Email Plugin's Groovy templates to dynamically set recipients, subject, and content based on build result and environment variables.
  • Token references like ${BUILD_URL}, ${BUILD_NUMBER}, ${JOB_NAME} are case-sensitive and must match the exact token name from the plugin documentation.
  • For email attachments, use the 'Attachments' field in the Email Extension post-build action; wildcards like '*.xml' work but be mindful of file size limits.
  • Test SMTP connectivity directly with openssl s_client -connect smtp.gmail.com:587 -starttls smtp before debugging Jenkins config.
✦ Definition~90s read
What is Jenkins Email Notification Setup?

Jenkins email notification is the mechanism by which Jenkins sends emails to stakeholders about build results. It relies on an SMTP server to deliver messages. Jenkins provides two main approaches: the built-in mailer (jenkins-plugin:mailer) and the Email Extension Plugin (jenkins-plugin:email-ext).

Imagine you're a project manager who needs to automatically email status updates to your team after each project milestone.

The built-in mailer is simple but limited—it can only send emails to a fixed list of recipients with a static subject and body. The Email Extension Plugin, on the other hand, allows per-trigger configurations (success, failure, unstable, regression, aborted), custom templates using tokens, Groovy scripting, and attachments.

In production, the Email Extension Plugin is almost always the right choice because it integrates with pipeline steps like 'emailext' and gives you fine-grained control over notification behavior.

Plain-English First

Imagine you're a project manager who needs to automatically email status updates to your team after each project milestone. You have a robot assistant (Jenkins) that finishes tasks and can send emails, but you need to give it the right instructions: which email server to use (like Gmail or your company's mail server), the password to log in, and what the email should say. This article teaches you how to configure that robot so it sends clear, useful emails with links to the project details, and how to fix it when emails don't arrive.

I once spent a weekend debugging why Jenkins wasn't sending failure notifications. The pipeline was failing, but the team only found out Monday morning when a customer complained. The root cause? I had used the built-in mailer with a default recipient list that didn't include the right people, and the SMTP server silently rejected the 'from' address because the Jenkins URL was set to localhost. That incident taught me that email notification setup is not just a 'nice to have'—it's a critical part of your CI/CD reliability. This article covers everything I learned: from choosing between the built-in mailer and the Email Extension Plugin, to configuring SMTP for Gmail, SendGrid, or your internal server, to writing Groovy templates that dynamically adapt emails to build results. You'll also get a production debugging guide for when emails mysteriously fail.

SMTP Configuration: Gmail, SendGrid, and Internal SMTP

Configuring SMTP in Jenkins is done under 'Manage Jenkins > Configure System' in the 'E-mail Notification' and 'Extended E-mail Notification' sections. For production, use the Extended Email Plugin's SMTP settings, which override the built-in mailer.

Gmail SMTP Setup - SMTP server: smtp.gmail.com - Port: 587 (TLS) or 465 (SSL) - Use TLS: yes - Username: your full Gmail address (e.g., you@gmail.com) - Password: an App Password (not your regular password). Generate one at https://myaccount.google.com/apppasswords after enabling 2-Step Verification. - Test connection by clicking 'Test Configuration' — this sends a test email to the address in 'Default Recipients'.

SendGrid SMTP Setup - SMTP server: smtp.sendgrid.net - Port: 587 (TLS) - Use TLS: yes - Username: apikey - Password: your SendGrid API key (starts with 'SG.') - Ensure your SendGrid account has verified the sender email or domain to avoid being flagged as spam.

Internal SMTP (Postfix/Exchange) - Use your internal SMTP server hostname or IP. - Port: 25 (no auth) or 587 (auth). For internal servers, you may need to whitelist the Jenkins server IP. - If using auth, store credentials in Jenkins credentials store and reference them via the 'Use Credentials' dropdown. - Common issue: internal SMTP servers reject emails with 'from' addresses that don't match the authenticated user. Set the 'Default user e-mail suffix' in 'Extended E-mail Notification' to append a domain (e.g., @example.com) if needed.

Gmail App Password Gotcha
If you have 2-Step Verification enabled (you should), you MUST use an App Password. Your regular password will fail with 'Authentication failed'. Also, App Passwords are 16-character codes without spaces—copy them exactly.
Production Insight
We once had a SendGrid integration that worked in dev but failed in prod because the prod SendGrid account had a different API key scope. Always test with the exact credentials you'll use in production. Use Jenkins credentials binding to inject secrets securely.
Key Takeaway
Always test SMTP connectivity with openssl before configuring Jenkins: 'openssl s_client -connect smtp.gmail.com:587 -starttls smtp'.

Email Extension Plugin vs Built-in Mailer: When to Use Which

The built-in mailer (plugin ID: mailer) is sufficient for simple notifications: send an email to a fixed list when a build fails. It's configured under 'E-mail Notification' and can be used in freestyle jobs via 'Post-build Actions > E-mail Notification'. However, it lacks per-trigger control, custom templates, and pipeline support.

The Email Extension Plugin (plugin ID: email-ext) is the production standard. It provides: - Per-trigger configuration: success, failure, unstable, regression, aborted, still failing, etc. - Custom subject and body templates using tokens like ${BUILD_URL}, ${BUILD_NUMBER}, ${JOB_NAME}, ${PROJECT_NAME}, ${CHANGES}, ${FAILED_TESTS}. - Groovy scripting for dynamic content. - Attachments via the 'Attachments' field. - Pipeline step 'emailext' for declarative and scripted pipelines.

Migration path: If you're using the built-in mailer, switch to Email Extension by installing the plugin and reconfiguring your jobs. The built-in mailer will still work but you'll lose flexibility. For new projects, always use Email Extension.

Pipeline example: ``groovy emailext( subject: "Build ${env.JOB_NAME} - ${env.BUILD_NUMBER} ${currentBuild.result}", body: "See ${env.BUILD_URL} for details.", to: "team@example.com", attachmentsPattern: "*/target/.xml", replyTo: "no-reply@example.com", recipientProviders: [[$class: 'DevelopersRecipientProvider'], [$class: 'RequesterRecipientProvider']] ) `` Note: recipientProviders can dynamically add developers and requesters.

Plugin Compatibility
The Email Extension Plugin (version 2.100+) works with Jenkins 2.346.1+. The built-in mailer is deprecated in some Jenkins distributions but still available. Always check plugin compatibility in your Jenkins version.
Production Insight
In a past incident, a team used the built-in mailer with a static recipient list. When a developer left, they forgot to remove them, and sensitive build logs were sent to an inactive email that was later compromised. With Email Extension, you can use recipientProviders to dynamically include only the developers who committed changes, reducing exposure.
Key Takeaway
For any job that needs conditional or dynamic email notifications, use the Email Extension Plugin. The built-in mailer is only suitable for trivial, static notifications.

Gmail App-Specific Password Setup: Step-by-Step

If you use Gmail SMTP, you must generate an App Password. Here's the exact process: 1. Go to your Google Account: https://myaccount.google.com/security 2. Under 'Signing in to Google', enable '2-Step Verification' if not already enabled. 3. Once 2FA is on, go to 'App passwords' (search in the Google Account search bar or directly: https://myaccount.google.com/apppasswords). 4. Select 'Mail' as the app and 'Other (Custom name)' as the device. Give it a name like 'Jenkins CI'. 5. Click 'Generate'. You'll see a 16-character password (e.g., 'abcd efgh ijkl mnop'). Copy it immediately—you won't see it again. 6. In Jenkins, under 'Manage Jenkins > Configure System > E-mail Notification', enter: - SMTP server: smtp.gmail.com - Port: 587 - Use TLS: checked - User name: your full Gmail address - Password: the App Password (remove spaces if present; some Jenkins versions require no spaces) 7. Click 'Test Configuration' to verify.

Important: If you have a Google Workspace account, you may need to allow less secure apps or use OAuth2. App Passwords work for personal Gmail accounts with 2FA. For Workspace, consider using SendGrid or an internal SMTP for better control.

App Password Expiration
App Passwords do not expire unless you revoke them or change your Google Account password. However, if you rotate your account password, all App Passwords are invalidated. Generate a new one after any password change.
Production Insight
A colleague once stored the App Password in a Jenkins credential with 'secret text' type but forgot to bind it in the SMTP config. The SMTP field still had the old password. Always use credentials binding: in 'Extended E-mail Notification', check 'Use Credentials' and select the stored credential. This ensures secrets are managed centrally.
Key Takeaway
App Passwords are the only way to use Gmail SMTP with 2FA. Generate one per Jenkins instance and store it as a Jenkins credential.

Email Templates with Token References: ${BUILD_URL}, ${BUILD_NUMBER}, and More

The Email Extension Plugin supports tokens for dynamic content. Tokens are case-sensitive and must be enclosed in ${}. Common tokens: - ${BUILD_URL}: full URL to the build (e.g., http://jenkins.example.com/job/myjob/42/) - ${BUILD_NUMBER}: build number (e.g., 42) - ${JOB_NAME}: job name (e.g., myjob) - ${PROJECT_NAME}: same as JOB_NAME - ${CHANGES}: list of changes since last successful build - ${CHANGES_SINCE_LAST_SUCCESS}: detailed changes - ${FAILED_TESTS}: list of failed tests - ${ENV,var=MY_VAR}: environment variable value - ${SCRIPT,script="return jenkins.model.Jenkins.instance.displayName"}: Groovy script result

Customizing Subject and Body In the 'Extended E-mail Notification' section, you can set: - Default Subject: e.g., 'Build ${JOB_NAME} - ${BUILD_NUMBER} ${BUILD_STATUS}' - Default Body: e.g., '${BUILD_URL}

Changes: ${CHANGES}'

Per-Trigger Overrides For each trigger (Success, Failure, etc.), you can override the subject and body. This is useful for sending different messages based on result. Example for Failure trigger: - Subject: 'BUILD FAILED: ${JOB_NAME} #${BUILD_NUMBER}' - Body: 'Build failed at ${BUILD_URL}.

Failed tests: ${FAILED_TESTS}'

Token Reference Gotchas - Tokens are resolved at email-send time, not build time. So ${BUILD_URL} uses the Jenkins URL from configuration. - Some tokens like ${CHANGES} may be empty if the build is not a new build (e.g., rebuild). - Use ${BUILD_LOG_REGEX, regex='^ERROR:.*'} to include matching log lines.

Token Debugging
To see what a token resolves to, add ${TOKEN} to the email body and check the received email. Alternatively, use the Email Extension Plugin's 'Preview' feature in the job configuration (requires the 'Email Extension Template Preview' plugin).
Production Insight
We had a case where ${CHANGES} was empty in the email because the build was triggered by a timer, not by a code change. We fixed it by using ${CHANGES_SINCE_LAST_SUCCESS} instead, which includes all changes since the last successful build regardless of trigger.
Key Takeaway
Test your token templates with a non-critical build before deploying to production. Use ${BUILD_LOG_REGEX} for extracting specific log lines.

Email Attachment Patterns: Including Build Artifacts

The Email Extension Plugin can attach files from the workspace or other directories. The 'Attachments' field accepts a comma-separated list of patterns (Ant-style globs). For example: - '*/target/.xml' attaches all XML files under target directories recursively. - '.log, reports/.html' attaches log files in the workspace root and HTML files in the reports subdirectory.

Important considerations
  • File paths are relative to the workspace root. Use absolute paths if needed (e.g., '/var/log/jenkins/my.log') but ensure Jenkins has read permissions.
  • Large attachments can cause email delivery failures. Most SMTP servers have a size limit (e.g., 25MB for Gmail). Compress or exclude large files.
  • Use the 'Attachments Pattern' field in the 'Editable Email Notification' post-build action or in the pipeline step.

Pipeline example: ``groovy emailext( attachmentsPattern: '/target/surefire-report.xml, /target/failsafe-report.xml', subject: 'Test Reports', body: 'See attached.', to: 'qa@example.com' ) ``

Security: Be careful not to attach sensitive files like passwords or private keys. Use the 'Pre-send Script' (Groovy) to filter attachments if needed.

Attachment Size Limits
Gmail allows up to 25MB per email. SendGrid has a 30MB limit. If your attachments exceed this, consider uploading them to a shared location (e.g., S3) and including a link in the email instead.
Production Insight
I once accidentally attached the entire workspace (~2GB) because I used '**' as the pattern. Jenkins tried to send the email for 10 minutes before timing out, and the build was marked as unstable. Set explicit patterns and test with a small build first.
Key Takeaway
Always use specific glob patterns for attachments. Avoid '**' alone. Test attachment size with a small build before rolling out.

Per-Trigger Email Configuration: Success, Failure, Unstable, Regression, Aborted

The Email Extension Plugin allows you to configure different email behaviors for each build result. Under 'Post-build Actions > Editable Email Notification', click 'Add Trigger' to select from: - Success - Failure - Unstable - Regression - Aborted - Still Failing - Still Unstable - Fixed - Improvement - etc.

For each trigger, you can customize
  • Recipient List: who gets the email (overrides global list)
  • Subject: tokenized subject
  • Body: tokenized body
  • Attachments Pattern: files to attach
  • Send To: recipients (Developers, Requester, etc.)
Production pattern
  • Failure: send to all developers and the build requester, include failed tests and console log excerpt.
  • Success: send only to the requester with a short summary.
  • Unstable: send to developers with test failure details.
  • Aborted: send to requester only, no attachments.
Example configuration for Failure trigger
  • Recipient List: ${{DEFAULT_RECIPIENTS}}, ${{DEVELOPERS}}
  • Subject: 'BUILD FAILED: ${JOB_NAME} #${BUILD_NUMBER}'
  • Body: 'Build failed at ${BUILD_URL}.

Changes: ${CHANGES}

Failed tests: ${FAILED_TESTS}' - Attachments: '*/target/test-results/.xml'

Pipeline equivalent: ``groovy emailext( to: 'team@example.com', subject: "Build ${env.JOB_NAME} - ${env.BUILD_NUMBER} ${currentBuild.result}", body: "", recipientProviders: [[$class: 'DevelopersRecipientProvider']], attachBuildLog: true, compressBuildLog: true ) `` Note: attachBuildLog and compressBuildLog are useful for failure emails.

Recipient Providers
Use recipientProviders to dynamically include developers who made changes (DevelopersRecipientProvider) or the user who triggered the build (RequesterRecipientProvider). This avoids hardcoding emails.
Production Insight
We had a regression where emails were sent to the entire org because the 'Default Recipients' field was set to a mailing list. For failure emails, we now use recipientProviders with a small group of on-call engineers to reduce noise.
Key Takeaway
Configure per-trigger emails to match the severity: failure should be loud (many recipients, details), success should be quiet (only if requested).

Extended Email Plugin Groovy Templates: Dynamic Content with Script

The Email Extension Plugin supports Groovy scripts for advanced customization. You can use a 'Pre-send Script' or a 'Groovy Template' for the email body.

Pre-send Script: This Groovy script runs before the email is sent. It can modify the MimeMessage object, add headers, or conditionally cancel sending. Example: ```groovy import javax.mail.Message.RecipientType import javax.mail.internet.InternetAddress

if (build.result == hudson.model.Result.SUCCESS) { // Only send to requester for success msg.setRecipients(RecipientType.TO, build.getCauses()[0].getUser()?.getProperty(hudson.model.UserProperty.class)?.getEmailAddress() ?: 'default@example.com') } ```

Groovy Template Body: Instead of plain text, you can write a Groovy template that returns a string. This is powerful for generating HTML emails with tables. Example: ``groovy def buildUrl = build.getAbsoluteUrl() def result = build.result.toString() def changes = build.getChangeSet()?.getItems()?.collect { "${it.author.displayName}: ${it.msg}" }?.join(' ') return """ <html> <body> <h2>Build ${result}</h2> <p>Job: ${build.parent.displayName} #${build.number}</p> <p><a href="${buildUrl}">${buildUrl}</a></p> <h3>Changes:</h3> <pre>${changes}</pre> </body> </html> """ ``

How to configure: 1. In 'Editable Email Notification', set 'Content Type' to 'text/html'. 2. In 'Default Body', enter your Groovy template or select 'Groovy Template File' to use a file from Jenkins home. 3. For Pre-send Script, check 'Advanced Settings' and paste the script.

Production use case: Dynamically set recipients based on build result and environment. Example script to not send emails for successful builds in a staging environment: ``groovy if (build.result == hudson.model.Result.SUCCESS && env.getEnvironment()['ENV'] == 'staging') { cancel = true } ``

Testing Groovy Scripts
Production Insight
I once wrote a Groovy template that sent an HTML email with a table of test results. The email was perfect in development but broke in production because the production Jenkins had an older version of the Email Extension plugin that didn't support a certain method. Always test Groovy scripts in the target environment.
Key Takeaway
Groovy templates give you unlimited flexibility but require testing. Use pre-send scripts to conditionally cancel or modify emails based on build state.

Troubleshooting Email Delivery Failures: A Systematic Approach

  1. Check Jenkins logs: Look at 'Manage Jenkins > System Log' for email-related messages. Also check 'jenkins.log' on disk. Search for 'email' or 'mail'.
  2. Test SMTP connectivity: From the Jenkins server, test the SMTP server directly:
  3. - Gmail: openssl s_client -connect smtp.gmail.com:587 -starttls smtp
  4. - SendGrid: openssl s_client -connect smtp.sendgrid.net:587 -starttls smtp
  5. - Internal: telnet smtp.internal.com 25
  6. If the connection fails, it's a network issue (firewall, DNS).
  7. Verify credentials: Use 'Test Configuration' in Jenkins SMTP settings. If it fails, check username/password. For Gmail, ensure you're using an App Password.
  8. Check 'from' address: Many SMTP servers validate the 'from' address. Ensure it's a real address or one allowed by your server. Set 'Default user e-mail suffix' if needed.
  9. Check Jenkins URL: As mentioned, a misconfigured Jenkins URL can cause 'from' address issues. Set it to a public URL.
  10. Check trigger configuration: Ensure the trigger (e.g., Failure) is enabled and the recipient list is not empty. Use 'Trigger' dropdown in 'Editable Email Notification'.
  11. Check email logs: If your SMTP server provides logs (e.g., SendGrid Event Webhook), check them for delivery failures or bounces.
  12. Enable debug logging: In Jenkins, set the system property mail.debug=true by adding -Dmail.debug=true to Jenkins startup arguments. This prints SMTP conversation to logs.
  13. Use a test job: Create a simple freestyle job with a single 'emailext' step to isolate the issue.
Common error messages
  • 'javax.mail.AuthenticationFailedException': wrong username/password.
  • 'com.sun.mail.smtp.SMTPSendFailedException: 550 5.1.1 ... User unknown': recipient address invalid.
  • 'com.sun.mail.smtp.SMTPSendFailedException: 554 5.7.1 ... Relay access denied': SMTP server doesn't allow relaying; check authentication and 'from' address.
Production Debugging
Never enable mail.debug on a production Jenkins without careful consideration—it may log SMTP credentials. Use it temporarily and disable after debugging.
Production Insight
We once had a DNS issue where the internal SMTP server hostname resolved to a different IP in the Jenkins server's /etc/hosts. The telnet test worked from the command line but Jenkins used a different DNS resolver. We fixed it by adding the correct hostname to /etc/hosts.
Key Takeaway
Systematically test each layer: network connectivity, SMTP authentication, 'from' address, Jenkins URL, and trigger configuration. Use mail.debug as last resort.

Securing Email Credentials: Using Jenkins Credentials Store

Never hardcode SMTP passwords in Jenkins configuration. Use the Jenkins Credentials Store to manage secrets securely.

Steps: 1. Go to 'Manage Jenkins > Manage Credentials'. 2. Add a new credential of type 'Username with password' or 'Secret text'. 3. For SMTP, 'Username with password' is ideal: username is the SMTP user, password is the App Password or API key. 4. In 'Extended E-mail Notification' SMTP settings, check 'Use Credentials' and select the credential you created.

Pipeline binding: ``groovy withCredentials([usernamePassword(credentialsId: 'smtp-cred', usernameVariable: 'SMTP_USER', passwordVariable: 'SMTP_PASS')]) { emailext( subject: 'Build', body: 'Done', to: 'team@example.com', mimeType: 'text/plain' ) } `` Note: The emailext step does not directly use the variables; you need to configure the SMTP server in Jenkins global config to use the credential ID. The withCredentials is useful for other steps that need SMTP credentials.

Best practices
  • Use separate credentials for each environment (dev, staging, prod).
  • Rotate credentials periodically, especially if a team member leaves.
  • Audit credential usage in Jenkins logs (check 'com.cloudbees.plugins.credentials' log level).

Avoid: Storing passwords in plain text in config.xml files. If you must use the built-in mailer, at least use credentials binding in the SMTP config.

Credential Scopes
Set credential scope to 'System' if it's used globally (e.g., SMTP). 'Global' scope allows use in jobs. 'System' scope restricts to Jenkins internals.
Production Insight
We had a security audit that flagged SMTP passwords stored in plain text in Jenkins config.xml. We migrated all credentials to the Jenkins Credentials Store using the 'Username with password' type and removed the plain text entries. This satisfied the auditor and improved security.
Key Takeaway
Always use the Jenkins Credentials Store for SMTP passwords. Never store secrets in plain text in job configurations or global settings.

Email Notification in Pipelines: Declarative vs Scripted

In Jenkins pipelines, email notification can be integrated at various stages. The 'emailext' step is the recommended way.

Declarative Pipeline Example: ``groovy pipeline { agent any stages { stage('Build') { steps { echo 'Building...' } } } post { success { emailext( subject: "SUCCESS: ${env.JOB_NAME} #${env.BUILD_NUMBER}", body: "Build succeeded. See ${env.BUILD_URL}.", to: 'team@example.com' ) } failure { emailext( subject: "FAILURE: ${env.JOB_NAME} #${env.BUILD_NUMBER}", body: "Build failed. See ${env.BUILD_URL}.", to: 'team@example.com', attachLog: true ) } } } ``

Scripted Pipeline Example: ``groovy node { try { stage('Build') { echo 'Building...' } currentBuild.result = 'SUCCESS' } catch (Exception e) { currentBuild.result = 'FAILURE' throw e } finally { emailext( subject: "${currentBuild.result}: ${env.JOB_NAME} #${env.BUILD_NUMBER}", body: "Build ${currentBuild.result}. URL: ${env.BUILD_URL}", to: 'team@example.com' ) } } ``

Important: In declarative pipelines, the 'post' section is evaluated after the build result is set. Use 'always' to send email regardless of result, or use conditions like 'success', 'failure', 'unstable', 'changed'.

Gotcha: The 'emailext' step inherits global SMTP settings. If you need to override recipients or subject per pipeline, pass them as parameters.

Pipeline Environment Variables
Use env.BUILD_NUMBER, env.JOB_NAME, env.BUILD_URL in pipeline steps. These are set automatically by Jenkins and are case-sensitive.
Production Insight
We had a pipeline where the email was sent before the build result was finalized because the 'emailext' was placed in a stage step instead of the post section. This caused the subject to always say 'null'. Always use 'post' in declarative pipelines to ensure currentBuild.result is set.
Key Takeaway
Use the 'post' section in declarative pipelines for email notifications. In scripted pipelines, use try-catch-finally to ensure emails are sent even on failures.

Advanced: Custom Email Triggers and Content with Extended Email

Beyond the standard triggers, the Email Extension Plugin offers advanced triggers like 'Still Failing', 'Still Unstable', 'Fixed', 'Improvement', and 'Regression'. These are useful for reducing noise.

Example Use Cases
  • 'Still Failing': Send an email only on the first failure, then on every nth failure (using 'Failure' trigger with 'Send to' set to 'Only individuals who wrote code' and 'Still Failing' with a different subject).
  • 'Fixed': When a previously failing build succeeds, send a 'Fixed' notification with a summary of what was fixed.
  • 'Regression': When a build introduces new failures compared to the previous build.

Custom Content with Groovy: You can use a Groovy script to generate the email body dynamically. For example, to include the console log only for failures: ``groovy if (build.result == hudson.model.Result.FAILURE) { return build.getLog(100) } else { return 'Build succeeded.' } ``

Token Expansion in Attachments: You can use tokens in the attachments pattern, e.g., '*/target/${BUILD_NUMBER}/.xml'. However, this is rarely needed.

Multiple Email Notifications: You can add multiple 'Editable Email Notification' post-build actions to send different emails to different audiences. For example, one for developers (with details) and one for management (with summary).

Trigger Order
Triggers are evaluated in the order they appear. If multiple triggers match (e.g., 'Failure' and 'Still Failing'), both emails are sent unless you use 'Pre-send Script' to cancel duplicates.
Production Insight
We used 'Still Failing' to send a daily digest email for a job that runs hourly. We configured 'Failure' to send immediately to the on-call engineer, and 'Still Failing' to send a summary to the team every 6 hours. This reduced alert fatigue.
Key Takeaway
Leverage advanced triggers like 'Still Failing' and 'Fixed' to reduce noise. Use multiple email actions to target different audiences.

Testing Email Configuration: Sandbox and Validation Techniques

Before rolling out email notifications to production, test thoroughly.

1. Use a test SMTP server: Tools like MailHog (https://github.com/mailhog/MailHog) or FakeSMTP (https://github.com/Nilhcem/FakeSMTP) run locally and capture all emails. Configure Jenkins to use localhost:1025 (MailHog default). This lets you inspect emails without sending real ones.

2. Create a test job: A simple freestyle job with a single build step that echoes 'hello' and an 'Editable Email Notification' post-build action. Use different triggers to verify each one.

3. Validate tokens: Use the 'Preview' feature in the job configuration (requires 'Email Extension Template Preview' plugin). It shows the rendered subject and body.

4. Check attachment patterns: Create a test workspace with dummy files and verify the pattern matches correctly.

5. Use Jenkins CLI to test: You can trigger a build and check logs with: ``bash java -jar jenkins-cli.jar -s http://localhost:8080 build test-job -s -v `` Then check the console output for email-related messages.

6. Automate testing: Write a Jenkins pipeline that builds a test job and asserts that an email was sent (by checking MailHog API). Example: ``groovy stage('Test Email') { steps { build job: 'test-email-job', wait: true // Use MailHog API to check if email was received sh 'curl -s http://mailhog:8025/api/v2/messages | jq ".items[0].Content.Headers.Subject"' } } ``

Production Email Testing
Never test email notifications on production Jenkins with real recipients. Use a test SMTP server or a dedicated test job that sends to a controlled email address (e.g., your personal email).
Production Insight
We set up MailHog as a Docker container on our Jenkins server and configured a separate Jenkins instance for testing. This caught a bug where the attachment pattern was wrong before it reached production.
Key Takeaway
Always test email configurations in a sandbox environment. Use tools like MailHog to capture emails without delivering them.
● Production incidentPOST-MORTEMseverity: high

The Silent SMTP Rejection: How a Misconfigured Jenkins URL Killed Notifications

Symptom
Jenkins console output showed 'Email was triggered for: Failure' and 'Sending email...' with no error, but recipients never received the email.
Assumption
I assumed the SMTP server was misconfigured or the network blocked port 587.
Root cause
The Jenkins URL in 'Manage Jenkins > Configure System > Jenkins Location' was set to 'http://localhost:8080'. The Email Extension plugin uses this URL to construct the 'from' address (e.g., 'jenkins@localhost'), which Gmail SMTP rejected because the domain was not valid.
Fix
Set the Jenkins URL to the public-facing URL (e.g., 'https://ci.example.com') and restarted Jenkins. Emails started arriving immediately.
Key lesson
  • Always verify the Jenkins URL is a valid, reachable domain—it affects not only emails but also links in notifications and integration with other tools.
Production debug guideSymptom → Root cause → Fix4 entries
Symptom · 01
Email not sent; console shows 'Failed to send email' with javax.mail.AuthenticationFailedException
Fix
Check SMTP credentials. For Gmail, ensure you're using an App Password, not your regular password. Generate one at https://myaccount.google.com/apppasswords. For SendGrid, username is 'apikey' and password is the API key.
Symptom · 02
Email sent but never arrives; no error in Jenkins logs
Fix
Check the 'from' address and Jenkins URL. The 'from' address must be a real address or one allowed by your SMTP server. Set Jenkins URL to a valid public domain under 'Manage Jenkins > Configure System > Jenkins Location'.
Symptom · 03
Email arrives but with broken links (e.g., http://localhost:8080)
Fix
Set the Jenkins URL to the correct public URL. Also update any tokens that use ${BUILD_URL}—they rely on this setting.
Symptom · 04
Email Extension plugin says 'Triggered' but no email sent for specific trigger (e.g., unstable)
Fix
Check the per-trigger configuration. Ensure the trigger is enabled and the recipient list is not empty. Also verify that the build result matches the trigger (e.g., unstable vs failure).
★ Jenkins Email Notification Setup Quick Referenceprint this for your desk
Authentication failed
Immediate action
Verify SMTP credentials
Commands
echo | openssl s_client -connect smtp.gmail.com:587 -starttls smtp 2>/dev/null | grep '250-AUTH'
Check that password is an App Password for Gmail
Fix now
Set correct credentials in Jenkins > Configure System > E-mail Notification
Email not delivered, no error+
Immediate action
Check Jenkins URL
Commands
curl -sI http://localhost:8080/login | grep 'Location'
Check 'Manage Jenkins > Configure System > Jenkins Location'
Fix now
Set Jenkins URL to https://ci.example.com
Broken links in email+
Immediate action
Update Jenkins URL
Commands
grep 'jenkinsUrl' /var/lib/jenkins/jenkins.model.JenkinsLocationConfiguration.xml
Fix now
Set Jenkins URL to public-facing URL
Email not sent for unstable build+
Immediate action
Check per-trigger config
Commands
grep -A10 'unstable' /var/lib/jenkins/jobs/myjob/config.xml
Verify recipient list is not empty
Fix now
Enable 'Unstable' trigger and add recipients
Attachment missing+
Immediate action
Check attachment pattern
Commands
ls -la workspace/*.xml
Verify path relative to workspace
Fix now
Use absolute path or correct relative path in 'Attachments' field
Email Extension Plugin vs Built-in Mailer Comparison
FeatureBuilt-in MailerEmail Extension PluginRecommendation
Per-trigger configurationNo (single trigger for failure)Yes (success, failure, unstable, regression, aborted, etc.)Use Email Extension
Custom subject/body tokensLimited ($BUILD_URL, $BUILD_NUMBER)Full token support (${BUILD_URL}, ${CHANGES}, ${FAILED_TESTS}, etc.)Use Email Extension
Groovy scriptingNoYes (pre-send script, Groovy template body)Use Email Extension
AttachmentsNoYes (glob patterns)Use Email Extension
Pipeline supportNo (mail step deprecated)Yes (emailext step)Use Email Extension
Ease of setupSimple (2 fields)Moderate (many options)Email Extension for flexibility
SMTP configurationShared with global settingsCan override per jobEmail Extension
Production readinessBasicAdvanced (recipient providers, triggers)Email Extension
📦 Downloadable Quick Reference

Print-friendly master reference covering all topics in this track.

⇩ Download PDF

Key takeaways

1
Use the Email Extension Plugin for all production email notifications; avoid the built-in mailer.
2
For Gmail SMTP, always use an App Password generated from your Google Account with 2FA enabled.
3
Set Jenkins URL to a public-facing domain to ensure 'from' addresses are valid and links work.
4
Store SMTP credentials in Jenkins Credentials Store, never in plain text.
5
Leverage per-trigger configurations to send different emails for success, failure, unstable, etc.
6
Use tokens like ${BUILD_URL}, ${BUILD_NUMBER}, ${CHANGES}, and ${FAILED_TESTS} for dynamic content.
7
Test SMTP connectivity with openssl before configuring Jenkins.
8
Use recipientProviders to dynamically include developers and requesters instead of hardcoding emails.

Common mistakes to avoid

6 patterns
×

Using regular Gmail password instead of App Password

Symptom
AuthenticationFailedException
Fix
Generate an App Password from Google Account and use that in Jenkins SMTP settings.
×

Setting Jenkins URL to localhost

Symptom
Emails not delivered or 'from' address rejected
Fix
Set Jenkins URL to public-facing domain in 'Manage Jenkins > Configure System > Jenkins Location'.
×

Using built-in mailer for complex pipelines

Symptom
Cannot customize per trigger or add attachments
Fix
Install Email Extension Plugin and migrate to 'Editable Email Notification' post-build action.
×

Hardcoding SMTP password in config.xml

Symptom
Security audit failure; password exposed
Fix
Use Jenkins Credentials Store to store SMTP credentials and reference them in SMTP settings.
×

Not testing SMTP connectivity before configuring Jenkins

Symptom
Emails fail with timeout or connection refused
Fix
Use openssl or telnet to test SMTP server reachability and authentication.
×

Using wrong token syntax (e.g., $BUILD_URL instead of ${BUILD_URL})

Symptom
Token not resolved in email
Fix
Use ${} syntax for all tokens. Check plugin documentation for exact token names.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
How do you configure Jenkins to send email notifications using Gmail SMT...
Q02SENIOR
What is the difference between the built-in mailer and the Email Extensi...
Q03SENIOR
How would you dynamically set email recipients based on who committed ch...
Q04JUNIOR
What tokens would you use to include the build URL and test results in a...
Q05SENIOR
How do you debug an email that is not being sent even though the trigger...
Q06SENIOR
Can you send HTML emails with the Email Extension Plugin?
Q07JUNIOR
How do you attach files from the workspace to an email?
Q08SENIOR
What is the purpose of the 'Pre-send Script' in the Email Extension Plug...
Q01 of 08SENIOR

How do you configure Jenkins to send email notifications using Gmail SMTP?

ANSWER
Install Email Extension Plugin, then go to Manage Jenkins > Configure System > Extended E-mail Notification. Set SMTP server to smtp.gmail.com, port 587, check 'Use TLS', username as full Gmail address, password as an App Password (generated from Google Account with 2FA enabled). Click 'Test Configuration' to verify.
FAQ · 8 QUESTIONS

Frequently Asked Questions

01
Why are my emails not being sent even though the build shows 'Email was triggered'?
02
How do I generate an App Password for Gmail?
03
Can I send emails to multiple recipients with different content?
04
What is the maximum attachment size for email notifications?
05
How do I include the console log in the email?
06
Why are my token values not appearing in the email?
07
Can I send emails only to the person who triggered the build?
08
How do I test email configuration without sending real emails?
N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Written from production experience, not tutorials.

Follow
Verified
production tested
July 09, 2026
last updated
230
articles · all by Naren
🔥

That's Jenkins. Mark it forged?

10 min read · try the examples if you haven't

Previous
Jenkins REST API & CLI Automation
37 / 39 · Jenkins
Next
Jenkins Environment Variables Reference