diff --git src/wp-includes/pluggable.php src/wp-includes/pluggable.php
index c4e271518b..1b36b52cfe 100644
--- src/wp-includes/pluggable.php
+++ src/wp-includes/pluggable.php
@@ -183,6 +183,24 @@ function wp_mail( $to, $subject, $message, $headers = '', $attachments = array()
 	 */
 	$atts = apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) );
 
+	/**
+	 * Filter whether to preempt sending an email.
+	 *
+	 * Passing a truthy value will effectively short-circuit {@see wp_mail()},
+	 * returning that value instead.
+	 *
+	 * @since 4.5.0
+	 *
+	 * @param bool  $return Short-circuit return value.
+	 * @param array $args   A compacted array of wp_mail() arguments, including the "to" email,
+	 *                      subject, message, headers, and attachments values.
+	 */
+	$pre_wp_mail = apply_filters( 'pre_wp_mail', null, $atts );
+
+	if ( ! is_null ( $pre_wp_mail ) ) {
+		return $pre_wp_mail;
+	}
+
 	if ( isset( $atts['to'] ) ) {
 		$to = $atts['to'];
 	}
diff --git tests/phpunit/tests/mail.php tests/phpunit/tests/mail.php
index 1522594b0d..a4a8fb2d1d 100644
--- tests/phpunit/tests/mail.php
+++ tests/phpunit/tests/mail.php
@@ -392,4 +392,15 @@ class Tests_Mail extends WP_UnitTestCase {
 		$this->assertEquals( 'wp_mail_failed', $call_args[0]->get_error_code() );
 		$this->assertEquals( $expected_error_data, $call_args[0]->get_error_data() );
 	}
+
+	/**
+	 * @ticket 35069
+	 */
+	public function test_wp_mail_bail_early() {
+		$this->assertTrue( wp_mail( WP_TESTS_EMAIL, 'Foo', 'Bar' ) );
+
+		add_filter( 'pre_wp_mail', '__return_null' );
+		$this->assertNull( wp_mail( WP_TESTS_EMAIL, 'Foo', 'Bar' ) );
+		remove_filter( 'pre_wp_mail', '__return_null' );
+	}
 }
