SysTutorials

Configuring Email Notifications for Git Push Events

· updated April 11, 2026

Sending email notifications when commits are pushed to a central Git repository helps teams stay coordinated and maintains audit trails. This is handled through Git hooks—scripts triggered by repository events.

How Post-Receive Hooks Work

When a client pushes to your Git server, the post-receive hook executes automatically. This hook lives at GIT_DIR/hooks/post-receive in your bare repository. You place an executable script there that generates and sends notification emails containing commit details, diffs, and metadata.

A typical notification email includes:

Installing Mail Dependencies

You need a mail transport agent to send emails. On modern systems, heirloom-mailx or msmtp provide the most reliable interface.

On Fedora/RHEL/CentOS 9+:

sudo dnf install heirloom-mailx

On Debian/Ubuntu:

sudo apt install heirloom-mailx

Use heirloom-mailx specifically—default alternatives lack options like -r (sender address) that hook scripts need.

If you don’t have a local mail service running, the hook can use SMTP directly instead (covered in the SMTP section below).

Creating the Post-Receive Hook

Git ships with a reference implementation. Find it on your system:

find /usr/share/git-core/contrib/hooks -name "post-receive.sample" 2>/dev/null

Or download the current version from the Git repository:

curl -o post-receive \
  https://raw.githubusercontent.com/git/git/master/contrib/hooks/post-receive.sample

If you prefer to write your own minimal hook, here’s a practical example:

#!/bin/bash

# Read configuration from repository config
REPO_NAME=$(git rev-parse --absolute-git-dir | xargs basename)
MAILINGLIST=$(git config hooks.mailinglist)
EMAILPREFIX=$(git config hooks.emailprefix "[GIT]")
SENDEREMAIL=$(git config hooks.senderEmail "git-notify@localhost")

# Process each ref that was pushed
while read oldrev newrev refname; do
  # Skip branch deletions
  [ "$newrev" = "0000000000000000000000000000000000000000" ] && continue

  BRANCH=$(basename "$refname")
  COMMIT_MSG=$(git log -1 --format=%s "$newrev")
  SUBJECT="$EMAILPREFIX [$REPO_NAME:$BRANCH] $COMMIT_MSG"

  # Build the email body
  {
    echo "Repository: $REPO_NAME"
    echo "Branch: $BRANCH"
    echo "Pushed by: $(git log -1 --format=%an $newrev)"
    echo "Commit: $newrev"
    echo "Date: $(git log -1 --format=%aI $newrev)"
    echo ""
    echo "=== Commit Message ==="
    git log -1 --format=%B "$newrev"
    echo ""
    echo "=== Files Changed ==="
    git diff-tree --name-status -r "$oldrev" "$newrev"
    echo ""
    echo "=== Diff ==="
    git diff-tree -p "$oldrev" "$newrev"
  } | mailx -s "$SUBJECT" -r "$SENDEREMAIL" $MAILINGLIST
done

Installing the Hook

Copy the hook to your bare repository and make it executable:

cp post-receive /path/to/repo.git/hooks/post-receive
chmod 755 /path/to/repo.git/hooks/post-receive

For managing hooks across multiple repositories, use symlinks:

mkdir -p /opt/git-hooks
cp post-receive /opt/git-hooks/post-receive
chmod 755 /opt/git-hooks/post-receive

# Link to each repository
ln -sf /opt/git-hooks/post-receive /path/to/repo.git/hooks/post-receive

The script must be executable. If permissions are wrong, the hook silently fails—always test after installation.

Configuring Repository Settings

Store notification preferences in the repository config:

cd /path/to/repo.git
git config hooks.mailinglist "dev@example.com ops@example.com"
git config hooks.emailprefix "[DEPLOY]"
git config hooks.senderEmail "git-notify@example.com"
git config hooks.from "Git Notifications <git-notify@example.com>"

Or edit the config file directly:

[hooks]
    mailinglist = dev@example.com ops@example.com
    emailprefix = [DEPLOY]
    senderEmail = git-notify@example.com

Optionally, update the repository description (shown in email headers and gitweb):

echo "My Project Name" > /path/to/repo.git/description

Using SMTP Instead of Local Mail

If you don’t have a mail daemon running, configure the hook to use SMTP directly. Modify the mailx command in your hook:

echo "$email_body" | mailx \
  -S smtp="smtps://smtp.gmail.com:465" \
  -S smtp-use-starttls=no \
  -S smtp-auth="login" \
  -S smtp-auth-user="your-email@gmail.com" \
  -S smtp-auth-password="your-app-password" \
  -s "$SUBJECT" \
  -r "$SENDEREMAIL" \
  $MAILINGLIST

For Gmail: Use an App Password instead of your account password. Store credentials in ~/.mailrc with mode 600:

account gmail {
  set smtp="smtps://smtp.gmail.com:465"
  set smtp-auth="login"
  set smtp-auth-user="your-email@gmail.com"
  set smtp-auth-password="your-app-password"
}

Then reference it in the hook:

echo "$email_body" | mailx -A gmail -s "$SUBJECT" -r "$SENDEREMAIL" $MAILINGLIST

For msmtp: A cleaner alternative to mailx SMTP:

echo "$email_body" | msmtp -a default -t

Configure ~/.msmtprc:

account default
host smtp.gmail.com
port 465
security tls
auth login
user your-email@gmail.com
password your-app-password
from git-notify@example.com

Testing the Hook

Push a test commit to verify the hook executes:

cd /path/to/local/repo
git commit --allow-empty -m "Test notification hook"
git push origin main

Check for errors in server logs:

# Local mail service
tail -f /var/log/mail.log

# systemd journal
journalctl -u postfix -f

# Enable debug in mailx by adding -v flag to the hook command

Troubleshooting

Hook doesn’t execute:

Emails not being sent:

Missing or incomplete commit details:

Permission denied when hook tries to access Git:

Best Practices

← All posts