diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index 62908602e7be..c8e55b2613f5 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -600,6 +600,28 @@ the name of the file that holds the e-mail to be sent.  Exiting with a
 non-zero status causes `git send-email` to abort before sending any
 e-mails.
 
+The following environment variables are set when executing the hook.
+
+`GIT_SENDEMAIL_FILE_COUNTER`::
+	A 1-based counter incremented by one for every file holding an e-mail
+	to be sent (excluding any FIFOs). This counter does not follow the
+	patch series counter scheme. It will always start at 1 and will end at
+	GIT_SENDEMAIL_FILE_TOTAL.
+
+`GIT_SENDEMAIL_FILE_TOTAL`::
+	The total number of files that will be sent (excluding any FIFOs). This
+	counter does not follow the patch series counter scheme. It will always
+	be equal to the number of files being sent, whether there is a cover
+	letter or not.
+
+These variables may for instance be used to validate patch series.
+
+The sample `sendemail-validate` hook that comes with Git checks that all sent
+patches (excluding the cover letter) can be applied on top of the upstream
+repository default branch without conflicts. Some placeholders are left for
+additional validation steps to be performed after all patches of a given series
+have been applied.
+
 fsmonitor-watchman
 ~~~~~~~~~~~~~~~~~~
 
diff --git a/git-send-email.perl b/git-send-email.perl
index 07f2a0cbeaad..497ec0354790 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -795,11 +795,26 @@ sub is_format_patch_arg {
 @files = handle_backup_files(@files);
 
 if ($validate) {
+	# FIFOs can only be read once, exclude them from validation.
+	my @real_files = ();
 	foreach my $f (@files) {
 		unless (-p $f) {
-			validate_patch($f, $target_xfer_encoding);
+			push(@real_files, $f);
 		}
 	}
+
+	# Run the loop once again to avoid gaps in the counter due to FIFO
+	# arguments provided by the user.
+	my $num = 1;
+	my $num_files = scalar @real_files;
+	$ENV{GIT_SENDEMAIL_FILE_TOTAL} = "$num_files";
+	foreach my $r (@real_files) {
+		$ENV{GIT_SENDEMAIL_FILE_COUNTER} = "$num";
+		validate_patch($r, $target_xfer_encoding);
+		$num += 1;
+	}
+	delete $ENV{GIT_SENDEMAIL_FILE_COUNTER};
+	delete $ENV{GIT_SENDEMAIL_FILE_TOTAL};
 }
 
 if (@files) {
diff --git a/templates/hooks--sendemail-validate.sample b/templates/hooks--sendemail-validate.sample
new file mode 100755
index 000000000000..c898ee3ab167
--- /dev/null
+++ b/templates/hooks--sendemail-validate.sample
@@ -0,0 +1,84 @@
+#!/bin/sh
+
+# An example hook script to validate a patch (and/or patch series) before
+# sending it via email.
+#
+# The hook should exit with non-zero status after issuing an appropriate
+# message if it wants to prevent the email(s) from being sent.
+#
+# To enable this hook, rename this file to "sendemail-validate".
+#
+# By default, it will only check that the patch(es) can be applied on top of
+# the default upstream branch without conflicts. Replace the XXX placeholders
+# with appropriate checks according to your needs.
+
+set -e
+
+validate_cover_letter()
+{
+	file="$1"
+	# XXX: Add appropriate checks here (e.g. spell checking).
+}
+
+validate_patch()
+{
+	file="$1"
+	# Ensure that the patch applies without conflicts to the latest
+	# upstream version.
+	git am -3 "$file" || die "failed to apply patch on upstream repo"
+	# XXX: Add appropriate checks here (e.g. checkpatch.pl).
+}
+
+validate_series()
+{
+	# XXX: Add appropriate checks here (e.g. quick build, etc.).
+}
+
+die()
+{
+	echo "sendemail-validate: error: $*" >&2
+	exit 1
+}
+
+get_work_dir()
+{
+	git config --get sendemail.validateWorkdir || {
+		# Initialize it to a temp dir, if unset.
+		git config --add sendemail.validateWorkdir "$(mktemp -d)"
+		git config --get sendemail.validateWorkdir
+	}
+}
+
+get_upstream_url()
+{
+	git config --get remote.origin.url ||
+		die "cannot get remote.origin.url"
+}
+
+clone_upstream()
+{
+	workdir="$1"
+	url="$(get_upstream_url)"
+	rm -rf -- "$workdir"
+	git clone --depth=1 "$url" "$workdir" ||
+		die "failed to clone upstream repository"
+}
+
+# main -------------------------------------------------------------------------
+
+workdir=$(get_work_dir)
+if [ "$GIT_SENDEMAIL_FILE_COUNTER" = 1 ]; then
+	clone_upstream "$workdir"
+fi
+cd "$workdir"
+export GIT_DIR="$workdir/.git"
+
+if grep -q "^diff --git " "$1"; then
+	validate_patch "$1"
+else
+	validate_cover_letter "$1"
+fi
+
+if [ "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL" ]; then
+	validate_series || die "patch series was rejected"
+fi
