diff --git a/INSTALL b/INSTALL
index 8be860b67db10bbe96ffbad9ae86b25710784607..bfb3336f8ea8995f7fbdb39a6f54d813ecde9215 100644
--- a/INSTALL
+++ b/INSTALL
@@ -217,6 +217,14 @@ plugin section of the config file (default values are shown if applicable):
    release. LDAP support may also be compiled as a plugin called
    `sieve_storage_ldap'.
 
+ sieve_user_email =
+   The primary e-mail address for the user. This is used as a default when no
+   other appropriate address is available for sending messages. If this setting
+   is not configured, either the postmaster or null "<>" address is used as a
+   sender, depending on the action involved. This setting is important when
+   there is no message envelope to extract addresses from, such as when the
+   script is executed in IMAP.
+
  sieve_user_log =
    The path to the file where the user log file is written. If not configured, a
    default location is used. If the main user's personal Sieve (as configured
@@ -241,6 +249,10 @@ plugin section of the config file (default values are shown if applicable):
      "sender"         - The sender address is used (default).
      "recipient"      - The final recipient address is used.
      "orig_recipient" - The original recipient is used.
+     "user_email"     - The user's primary address is used. This is
+                        configured with the "sieve_user_email" setting. If
+                        that setting is unconfigured, "user_mail" is equal to
+                        "sender" (the default).
      "postmaster"     - The postmaster_address configured for the LDA.
      "<user@domain>"  - Redirected messages are always sent from user@domain.
                         The angle brackets are mandatory. The null "<>" address
diff --git a/doc/example-config/conf.d/90-sieve.conf b/doc/example-config/conf.d/90-sieve.conf
index f516ba42d61a4656d3214628063a319d90022ce4..edc952dbb2f9b52e59b95df2952e3fbc3bbe0f63 100644
--- a/doc/example-config/conf.d/90-sieve.conf
+++ b/doc/example-config/conf.d/90-sieve.conf
@@ -136,6 +136,14 @@ plugin {
   # (Currently only relevant for ManageSieve)
   #sieve_quota_max_storage = 0
 
+  # The primary e-mail address for the user. This is used as a default when no
+  # other appropriate address is available for sending messages. If this setting
+  # is not configured, either the postmaster or null "<>" address is used as a
+  # sender, depending on the action involved. This setting is important when
+  # there is no message envelope to extract addresses from, such as when the
+  # script is executed in IMAP.
+  #sieve_user_email =
+
   # The path to the file where the user log is written. If not configured, a
   # default location is used. If the main user's personal Sieve (as configured
   # with sieve=) is a file, the logfile is set to <filename>.log by default. If
@@ -148,6 +156,10 @@ plugin {
   #   "sender"         - The sender address is used (default).
   #   "recipient"      - The final recipient address is used.
   #   "orig_recipient" - The original recipient is used.
+  #   "user_email"     - The user's primary address is used. This is
+  #                      configured with the "sieve_user_email" setting. If
+  #                      that setting is unconfigured, "user_mail" is equal to
+  #                      "recipient".
   #   "postmaster"     - The postmaster_address configured for the LDA.
   #   "<user@domain>"  - Redirected messages are always sent from user@domain.
   #                      The angle brackets are mandatory. The null "<>" address
diff --git a/src/lib-sieve/cmd-redirect.c b/src/lib-sieve/cmd-redirect.c
index a2b006fa09cf0d067eed7e26aaa5261230ad3105..af3464949a43bd9d8f490aab1cbcdee44747d086 100644
--- a/src/lib-sieve/cmd-redirect.c
+++ b/src/lib-sieve/cmd-redirect.c
@@ -312,13 +312,12 @@ static int act_redirect_send
 {
 	static const char *hide_headers[] =
 		{ "Return-Path", "X-Sieve", "X-Sieve-Redirected-From" };
-
+	struct sieve_instance *svinst = aenv->svinst;
 	struct sieve_message_context *msgctx = aenv->msgctx;
 	const struct sieve_script_env *senv = aenv->scriptenv;
 	const char *sender;
 	const char *recipient = sieve_message_get_final_recipient(msgctx);
-	struct sieve_address_source env_from =
-		aenv->svinst->redirect_from;
+	struct sieve_address_source env_from = svinst->redirect_from;
 	struct istream *input;
 	struct ostream *output;
 	const char *error;
@@ -354,14 +353,20 @@ static int act_redirect_send
 		/* Envelope available */
 		sender = sieve_message_get_sender(msgctx);
 		if ( sender != NULL &&
-			sieve_address_source_get_address(&env_from,
+			sieve_address_source_get_address(&env_from, svinst,
 				senv, msgctx, aenv->flags, &sender) < 0 )
 			sender = NULL;
 	} else {
 		/* No envelope available */
-		if ( sieve_address_source_get_address(&env_from,
-			senv, msgctx, aenv->flags, &sender) <= 0 )
+		if ( (ret=sieve_address_source_get_address(&env_from, svinst,
+			senv, msgctx, aenv->flags, &sender)) < 0 ) {
 			sender = NULL;
+		} else if ( ret == 0 ) {
+			if ( svinst->user_email == NULL )
+				sender = NULL;
+			else
+				sieve_address_to_string(svinst->user_email);
+		}
 	}
 
 	/* Open SMTP transport */
diff --git a/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c b/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
index f14cd88b3023469de301c1ec85639180ef7b220d..4967b58ac420030dacb010ebf728138d90e392e1 100644
--- a/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+++ b/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
@@ -431,6 +431,7 @@ static int ntfy_mailto_send
 (const struct sieve_enotify_exec_env *nenv,
 	const struct sieve_enotify_action *nact, const char *recipient)
 {
+	struct sieve_instance *svinst = nenv->svinst;
 	const struct sieve_message_data *msgdata = nenv->msgdata;
 	const struct sieve_script_env *senv = nenv->scriptenv;
 	struct ntfy_mailto_context *mtctx =
@@ -467,13 +468,6 @@ static int ntfy_mailto_send
 		return 0;
 	}
 
-	/* Determine message from address */
-	if ( nact->from == NULL ) {
-		from = t_strdup_printf("Postmaster <%s>", senv->postmaster_address);
-	} else {
-		from = nact->from;
-	}
-
 	/* Determine which sender to use
 
 	   From RFC 5436, Section 2.3:
@@ -493,12 +487,23 @@ static int ntfy_mailto_send
 			env_from.type = SIEVE_ADDRESS_SOURCE_EXPLICIT;
 		}
 	}
-	if ( (ret=sieve_address_source_get_address(&env_from,
+	if ( (ret=sieve_address_source_get_address(&env_from, svinst,
 		senv, nenv->msgctx, nenv->flags, &from_smtp)) < 0 ) {
 		from_smtp = NULL;
 	} else if ( ret == 0 ) {
-		from_smtp = ( mtctx->from_normalized != NULL ?
-			mtctx->from_normalized : senv->postmaster_address );
+		if ( mtctx->from_normalized != NULL )
+			from_smtp = mtctx->from_normalized;
+		else if ( svinst->user_email != NULL )
+			from_smtp = sieve_address_to_string(svinst->user_email);
+		else
+			from_smtp = senv->postmaster_address;
+	}
+
+	/* Determine message from address */
+	if ( nact->from == NULL ) {
+		from = t_strdup_printf("<%s>", from_smtp);
+	} else {
+		from = nact->from;
 	}
 
 	/* Determine subject */
@@ -551,7 +556,7 @@ static int ntfy_mailto_send
 	}
 
 	msg = t_str_new(512);
-	outmsgid = sieve_message_get_new_id(nenv->svinst);
+	outmsgid = sieve_message_get_new_id(svinst);
 
 	rfc2822_header_write(msg, "X-Sieve", SIEVE_IMPLEMENTATION);
 	rfc2822_header_write(msg, "Message-ID", outmsgid);
diff --git a/src/lib-sieve/sieve-address-source.c b/src/lib-sieve/sieve-address-source.c
index c51d1c6dc9d01f474d4c0f5735ba6123f55e008d..e0124ec2447503db30c368e4a029a104f5aced79 100644
--- a/src/lib-sieve/sieve-address-source.c
+++ b/src/lib-sieve/sieve-address-source.c
@@ -33,6 +33,8 @@ bool sieve_address_source_parse
 			asrc->type = SIEVE_ADDRESS_SOURCE_RECIPIENT;
 		} else if ( strcmp(value, "orig_recipient") == 0 ) {
 			asrc->type = SIEVE_ADDRESS_SOURCE_ORIG_RECIPIENT;
+		} else if ( strcmp(value, "user_email") == 0 ) {
+			asrc->type = SIEVE_ADDRESS_SOURCE_USER_EMAIL;
 		} else if ( strcmp(value, "postmaster") == 0 ) {
 			asrc->type = SIEVE_ADDRESS_SOURCE_POSTMASTER;
 		} else if ( value[0] == '<' &&	value[val_len-1] == '>') {
@@ -70,6 +72,7 @@ bool sieve_address_source_parse_from_setting
 
 int sieve_address_source_get_address
 (struct sieve_address_source *asrc,
+	struct sieve_instance *svinst,
 	const struct sieve_script_env *senv,
 	struct sieve_message_context *msgctx,
 	enum sieve_execute_flags flags,
@@ -77,8 +80,12 @@ int sieve_address_source_get_address
 {
 	enum sieve_address_source_type type = asrc->type;
 
+	if ( type == SIEVE_ADDRESS_SOURCE_USER_EMAIL &&
+		svinst->user_email == NULL )
+		type = SIEVE_ADDRESS_SOURCE_RECIPIENT;
+
 	if ( (flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) != 0 ) {
-		switch ( asrc->type ) {
+		switch ( type ) {
 		case SIEVE_ADDRESS_SOURCE_SENDER:
 		case SIEVE_ADDRESS_SOURCE_RECIPIENT:
 		case SIEVE_ADDRESS_SOURCE_ORIG_RECIPIENT:
@@ -100,12 +107,15 @@ int sieve_address_source_get_address
 	case SIEVE_ADDRESS_SOURCE_ORIG_RECIPIENT:
 		*addr_r = sieve_message_get_orig_recipient(msgctx);
 		return 1;
-	case SIEVE_ADDRESS_SOURCE_EXPLICIT:
-		*addr_r = sieve_address_to_string(asrc->address);
+	case SIEVE_ADDRESS_SOURCE_USER_EMAIL:
+		*addr_r = sieve_address_to_string(svinst->user_email);
 		return 1;
 	case SIEVE_ADDRESS_SOURCE_POSTMASTER:
 		*addr_r = senv->postmaster_address;
 		return 1;
+	case SIEVE_ADDRESS_SOURCE_EXPLICIT:
+		*addr_r = sieve_address_to_string(asrc->address);
+		return 1;
 	case SIEVE_ADDRESS_SOURCE_DEFAULT:
 		break;
 	}
diff --git a/src/lib-sieve/sieve-address-source.h b/src/lib-sieve/sieve-address-source.h
index 7dad09bdafa952e34b37785477c1d9bb7595f1ce..d6bea2bada2e6de84988c74dbcefcbf5d8862964 100644
--- a/src/lib-sieve/sieve-address-source.h
+++ b/src/lib-sieve/sieve-address-source.h
@@ -11,6 +11,7 @@ enum sieve_address_source_type {
 	SIEVE_ADDRESS_SOURCE_SENDER,
 	SIEVE_ADDRESS_SOURCE_RECIPIENT,
 	SIEVE_ADDRESS_SOURCE_ORIG_RECIPIENT,
+	SIEVE_ADDRESS_SOURCE_USER_EMAIL,
 	SIEVE_ADDRESS_SOURCE_POSTMASTER,
 	SIEVE_ADDRESS_SOURCE_EXPLICIT
 };
@@ -28,10 +29,11 @@ bool sieve_address_source_parse_from_setting
 		const char *setting, struct sieve_address_source *asrc);
 
 int sieve_address_source_get_address
-(struct sieve_address_source *asrc,
-	const struct sieve_script_env *senv,
-	struct sieve_message_context *msgctx,
-	enum sieve_execute_flags flags,
-	const char **addr_r);
+	(struct sieve_address_source *asrc,
+		struct sieve_instance *svinst,
+		const struct sieve_script_env *senv,
+		struct sieve_message_context *msgctx,
+		enum sieve_execute_flags flags,
+		const char **addr_r);
 
 #endif
diff --git a/src/lib-sieve/sieve-common.h b/src/lib-sieve/sieve-common.h
index 2c505549b1ba451f2b672b0ab706caea281892b7..705f9d95f58c47f6df391a30eccdec8bc64c469d 100644
--- a/src/lib-sieve/sieve-common.h
+++ b/src/lib-sieve/sieve-common.h
@@ -201,6 +201,7 @@ struct sieve_instance {
 	size_t max_script_size;
 	unsigned int max_actions;
 	unsigned int max_redirects;
+	const struct sieve_address *user_email;
 	struct sieve_address_source redirect_from;
 };
 
diff --git a/src/lib-sieve/sieve-settings.c b/src/lib-sieve/sieve-settings.c
index 92fcb3d2f83eff93ccdeb5691c617a748748d3f4..8a967329380f7bed77899b5d2b1cb7f1f750c617 100644
--- a/src/lib-sieve/sieve-settings.c
+++ b/src/lib-sieve/sieve-settings.c
@@ -8,7 +8,8 @@
 #include "sieve-common.h"
 #include "sieve-limits.h"
 #include "sieve-error.h"
-#include "sieve-actions.h"
+#include "sieve-address.h"
+#include "sieve-address-source.h"
 #include "sieve-settings.h"
 
 #include <ctype.h>
@@ -204,6 +205,7 @@ bool sieve_setting_get_duration_value
 void sieve_settings_load
 (struct sieve_instance *svinst)
 {
+	const char *str_setting;
 	unsigned long long int uint_setting;
 	size_t size_setting;
 
@@ -228,6 +230,18 @@ void sieve_settings_load
 	(void)sieve_address_source_parse_from_setting(svinst,
 		svinst->pool, "sieve_redirect_envelope_from",
 		&svinst->redirect_from);
+
+	str_setting = sieve_setting_get(svinst, "sieve_user_email");
+	if ( str_setting != NULL && *str_setting != '\0' ) {
+		svinst->user_email =
+			sieve_address_parse_envelope_path
+				(svinst->pool, str_setting);
+		if ( svinst->user_email == NULL ) {
+			sieve_sys_warning(svinst,
+				"Invalid address value for setting "
+				"`sieve_user_email': `%s'", str_setting);
+		}
+	}
 }
 
 
diff --git a/tests/execute/smtp.svtest b/tests/execute/smtp.svtest
index 08cbdcd29df21fe8229869351ec25cb4fb5d2574..e3d762582bb8b173b94e32dfb8d2bf642901ef1d 100644
--- a/tests/execute/smtp.svtest
+++ b/tests/execute/smtp.svtest
@@ -188,3 +188,53 @@ test "Redirect from <> with [<explicit>]" {
 		test_fail "envelope sender incorrect";
 	}
 }
+
+test_result_reset;
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "timo@example.net";
+test_set "envelope.orig_to" "tss@example.net";
+
+test_config_set "sieve_redirect_envelope_from" "user_email";
+test_config_reload;
+
+test "Redirect from [user email - fallback default]" {
+	redirect "cras@example.net";
+
+	if not test_result_execute {
+		test_fail "failed to execute redirect";
+	}
+
+	test_message :smtp 0;
+
+	if not envelope :is "from" "timo@example.net" {
+		test_fail "envelope sender incorrect";
+	}
+}
+
+test_result_reset;
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "timo@example.net";
+test_set "envelope.orig_to" "tss@example.net";
+
+test_config_set "sieve_redirect_envelope_from" "user_email";
+test_config_set "sieve_user_email" "t.sirainen@example.net";
+test_config_reload;
+
+test "Redirect from [user email]" {
+	redirect "cras@example.net";
+
+	if not test_result_execute {
+		test_fail "failed to execute redirect";
+	}
+
+	test_message :smtp 0;
+
+	if envelope :is "from" "sirius@example.org" {
+		test_fail "envelope sender incorrect (not changed)";
+	}
+
+	if not envelope :is "from" "t.sirainen@example.net" {
+		test_fail "envelope sender incorrect";
+	}
+}
+
diff --git a/tests/extensions/enotify/mailto.svtest b/tests/extensions/enotify/mailto.svtest
index afee1531c07c1647e0968db1d2361bfc9360a8e4..82f47be845eb56a878ccef45c14fc1d9c845e9c6 100644
--- a/tests/extensions/enotify/mailto.svtest
+++ b/tests/extensions/enotify/mailto.svtest
@@ -423,3 +423,63 @@ test "Envelope config - recipient" {
 		test_fail "envelope recipient set incorrectly";
 	}
 }
+
+/*
+ * Envelope config - user_email
+ */
+
+test_set "message" text:
+From: stephan@example.org
+To: nico@frop.example.org
+Subject: Frop!
+
+Klutsefluts.
+.
+;
+
+test_set "envelope.from" "sirius@example.org";
+test_set "envelope.to" "bertus@frop.example.org";
+
+test_config_set "sieve_notify_mailto_envelope_from"
+	"user_email";
+test_config_set "sieve_user_email" "b.wortel@example.org";
+test_config_reload;
+test_config_reload :extension "enotify";
+test_result_reset;
+
+test "Envelope config - user_email" {
+	notify :from "nico@frop.example.org"
+		"mailto:stephan@example.org?cc=timo@example.com";
+
+	if not test_result_execute {
+		test_fail "failed to execute notify";
+	}
+
+	test_message :smtp 0;
+
+	if not header :is "from" "nico@frop.example.org" {
+		test_fail "from set incorrectly";
+	}
+
+	if not envelope :is "from" "b.wortel@example.org" {
+		test_fail "envelope sender set incorrectly";
+	}
+
+	if not envelope :is "to" "stephan@example.org" {
+		test_fail "envelope recipient set incorrectly";
+	}
+
+	test_message :smtp 1;
+
+	if not header :is "from" "nico@frop.example.org" {
+		test_fail "from set incorrectly";
+	}
+
+	if not envelope :is "from" "b.wortel@example.org" {
+		test_fail "envelope sender set incorrectly";
+	}
+
+	if not envelope :is "to" "timo@example.com" {
+		test_fail "envelope recipient set incorrectly";
+	}
+}