diff --git a/Makefile.am b/Makefile.am
index 128ea65443dc2af3667a07d5b0bfaa874a285ac3..62ea4386efe88ecc866ca420a998d82c09489801 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -162,6 +162,8 @@ test_cases = \
 	tests/extensions/metadata/execute.svtest \
 	tests/extensions/metadata/errors.svtest \
 	tests/extensions/vnd.dovecot/debug/execute.svtest \
+	tests/extensions/vnd.dovecot/environment/basic.svtest \
+	tests/extensions/vnd.dovecot/environment/variables.svtest \
 	tests/deprecated/notify/basic.svtest \
 	tests/deprecated/notify/mailto.svtest \
 	tests/deprecated/notify/errors.svtest \
diff --git a/configure.ac b/configure.ac
index 0d478385679573d56bb429e2a4911b88df4b675d..97a585c596afd71fe213aff57c545362f13870ad 100644
--- a/configure.ac
+++ b/configure.ac
@@ -211,6 +211,7 @@ src/lib-sieve/plugins/duplicate/Makefile
 src/lib-sieve/plugins/index/Makefile
 src/lib-sieve/plugins/vnd.dovecot/Makefile
 src/lib-sieve/plugins/vnd.dovecot/debug/Makefile
+src/lib-sieve/plugins/vnd.dovecot/environment/Makefile
 src/lib-sieve-tool/Makefile
 src/lib-managesieve/Makefile
 src/plugins/Makefile
diff --git a/src/lib-sieve/Makefile.am b/src/lib-sieve/Makefile.am
index bdc35c80c4978c5a2d275aaf8ae076c07efa68d2..98ae11f178897b31dc4a646659179a3ae7796564 100644
--- a/src/lib-sieve/Makefile.am
+++ b/src/lib-sieve/Makefile.am
@@ -78,6 +78,7 @@ plugins = \
 	$(extdir)/index/libsieve_ext_index.la \
 	$(extdir)/metadata/libsieve_ext_metadata.la \
 	$(extdir)/vnd.dovecot/debug/libsieve_ext_debug.la \
+	$(extdir)/vnd.dovecot/environment/libsieve_ext_vnd_environment.la \
 	$(unfinished_plugins)
 
 libdovecot_sieve_la_DEPENDENCIES = \
diff --git a/src/lib-sieve/plugins/environment/ext-environment-common.c b/src/lib-sieve/plugins/environment/ext-environment-common.c
index b8680c1f000bc91ddd7128b9eb5ac68ea3225ef4..9fd49ba6011b069013ff50e701c70b7707bd0e88 100644
--- a/src/lib-sieve/plugins/environment/ext-environment-common.c
+++ b/src/lib-sieve/plugins/environment/ext-environment-common.c
@@ -6,14 +6,10 @@
 
 #include "sieve-common.h"
 #include "sieve-extensions.h"
+#include "sieve-interpreter.h"
 
 #include "ext-environment-common.h"
 
-struct ext_environment_context {
-	HASH_TABLE(const char *,
-		   const struct sieve_environment_item *) environment_items;
-};
-
 /*
  * Core environment items
  */
@@ -30,71 +26,121 @@ static const struct sieve_environment_item *core_env_items[] = {
 static unsigned int core_env_items_count = N_ELEMENTS(core_env_items);
 
 /*
- * Registration
+ * Validator context
  */
 
-static void ext_environment_item_register
-(struct ext_environment_context *ectx,
-	const struct sieve_environment_item *item)
+struct ext_environment_interpreter_context {
+	HASH_TABLE(const char *,
+		   const struct sieve_environment_item *) environment_items;
+
+	unsigned int active:1;
+};
+
+static void ext_environment_interpreter_extension_free
+	(const struct sieve_extension *ext, struct sieve_interpreter *interp,
+		void *context);
+
+struct sieve_interpreter_extension environment_interpreter_extension = {
+	.ext_def = &environment_extension,
+	.free = ext_environment_interpreter_extension_free,
+};
+
+static struct ext_environment_interpreter_context *
+ext_environment_interpreter_context_create
+(const struct sieve_extension *this_ext, struct sieve_interpreter *interp)
 {
-	hash_table_insert(ectx->environment_items, item->name, item);
+	pool_t pool = sieve_interpreter_pool(interp);
+	struct ext_environment_interpreter_context *ctx;
+
+	ctx = p_new(pool, struct ext_environment_interpreter_context, 1);
+
+	hash_table_create
+		(&ctx->environment_items, default_pool, 0, str_hash, strcmp);
+
+	sieve_interpreter_extension_register
+		(interp, this_ext, &environment_interpreter_extension, (void *)ctx);
+	return ctx;
 }
 
-void sieve_ext_environment_item_register
-(const struct sieve_extension *ext, const struct sieve_environment_item *item)
+static void ext_environment_interpreter_extension_free
+(const struct sieve_extension *ext ATTR_UNUSED,
+	struct sieve_interpreter *interp ATTR_UNUSED, 	void *context)
 {
-	struct ext_environment_context *ectx =
-		(struct ext_environment_context *) ext->context;
+	struct ext_environment_interpreter_context *ctx =
+		(struct ext_environment_interpreter_context *)context;
 
-	ext_environment_item_register(ectx, item);
+	hash_table_destroy(&ctx->environment_items);
 }
 
-/*
- * Initialization
- */
-
-bool ext_environment_init
-(const struct sieve_extension *ext ATTR_UNUSED, void **context)
+static struct ext_environment_interpreter_context *
+ext_environment_interpreter_context_get
+(const struct sieve_extension *this_ext, struct sieve_interpreter *interp)
 {
-	struct ext_environment_context *ectx =
-		i_new(struct ext_environment_context, 1);
+	struct ext_environment_interpreter_context *ctx =
+		(struct ext_environment_interpreter_context *)
+		sieve_interpreter_extension_get_context(interp, this_ext);
 
+	if ( ctx == NULL )
+		ctx = ext_environment_interpreter_context_create(this_ext, interp);
+
+	return ctx;
+}
+
+void ext_environment_interpreter_init
+(const struct sieve_extension *this_ext, struct sieve_interpreter *interp)
+{
+	struct ext_environment_interpreter_context *ctx;
 	unsigned int i;
 
-	hash_table_create
-		(&ectx->environment_items, default_pool, 0, str_hash, strcmp);
+	/* Create our context */
+	ctx = ext_environment_interpreter_context_get(this_ext, interp);
 
 	for ( i = 0; i < core_env_items_count; i++ ) {
-		ext_environment_item_register(ectx, core_env_items[i]);
+		const struct sieve_environment_item *item = core_env_items[i];
+		hash_table_insert(ctx->environment_items, item->name, item);
 	}
 
-	*context = (void *) ectx;
-
-	return TRUE;
+	ctx->active = TRUE;
 }
 
-void ext_environment_deinit(const struct sieve_extension *ext)
+bool sieve_ext_environment_is_active
+(const struct sieve_extension *env_ext, struct sieve_interpreter *interp)
 {
-	struct ext_environment_context *ectx =
-		(struct ext_environment_context *) ext->context;
+	struct ext_environment_interpreter_context *ctx =
+		ext_environment_interpreter_context_get(env_ext, interp);
 
-	hash_table_destroy(&ectx->environment_items);
-	i_free(ectx);
+	return ( ctx != NULL && ctx->active );
 }
 
+/*
+ * Registration
+ */
+
+void sieve_environment_item_register
+(const struct sieve_extension *env_ext, struct sieve_interpreter *interp,
+	const struct sieve_environment_item *item)
+{
+	struct ext_environment_interpreter_context *ctx;
+
+	i_assert( sieve_extension_is(env_ext, environment_extension) );
+	ctx = ext_environment_interpreter_context_get(env_ext, interp);
+	hash_table_insert(ctx->environment_items, item->name, item);
+}
 
 /*
  * Retrieval
  */
 
 const char *ext_environment_item_get_value
-(const struct sieve_extension *ext, const char *name,
-	const struct sieve_script_env *senv)
+(const struct sieve_extension *env_ext,
+	const struct sieve_runtime_env *renv, const char *name)
 {
-	struct ext_environment_context *ectx =
-		(struct ext_environment_context *) ext->context;
+	struct ext_environment_interpreter_context *ctx =
+		ext_environment_interpreter_context_get(env_ext, renv->interp);
 	const struct sieve_environment_item *item =
-		hash_table_lookup(ectx->environment_items, name);
+		hash_table_lookup(ctx->environment_items, name);
+
+	i_assert( sieve_extension_is(env_ext, environment_extension) );
 
 	if ( item == NULL )
 		return NULL;
@@ -103,7 +149,7 @@ const char *ext_environment_item_get_value
 		return item->value;
 
 	if ( item->get_value != NULL )
-		return item->get_value(ext->svinst, senv);
+		return item->get_value(renv);
 
 	return NULL;
 }
@@ -119,10 +165,9 @@ const char *ext_environment_item_get_value
  */
 
 static const char *envit_domain_get_value
-(struct sieve_instance *svinst,
-	const struct sieve_script_env *senv ATTR_UNUSED)
+(const struct sieve_runtime_env *renv)
 {
-	return svinst->domainname;
+	return renv->svinst->domainname;
 }
 
 const struct sieve_environment_item domain_env_item = {
@@ -137,10 +182,9 @@ const struct sieve_environment_item domain_env_item = {
  */
 
 static const char *envit_host_get_value
-(struct sieve_instance *svinst,
-	const struct sieve_script_env *senv ATTR_UNUSED)
+(const struct sieve_runtime_env *renv)
 {
-	return svinst->hostname;
+	return renv->svinst->hostname;
 }
 
 const struct sieve_environment_item host_env_item = {
@@ -160,10 +204,9 @@ const struct sieve_environment_item host_env_item = {
  */
 
 static const char *envit_location_get_value
-(struct sieve_instance *svinst,
-	const struct sieve_script_env *senv ATTR_UNUSED)
+(const struct sieve_runtime_env *renv)
 {
-	switch ( svinst->env_location ) {
+	switch ( renv->svinst->env_location ) {
 	case SIEVE_ENV_LOCATION_MDA:
 		return "MDA";
 	case SIEVE_ENV_LOCATION_MTA:
@@ -190,10 +233,9 @@ const struct sieve_environment_item location_env_item = {
  */
 
 static const char *envit_phase_get_value
-(struct sieve_instance *svinst,
-	const struct sieve_script_env *senv ATTR_UNUSED)
+(const struct sieve_runtime_env *renv)
 {
-	switch ( svinst->delivery_phase ) {
+	switch ( renv->svinst->delivery_phase ) {
 	case SIEVE_DELIVERY_PHASE_PRE:
 		return "pre";
 	case SIEVE_DELIVERY_PHASE_DURING:
diff --git a/src/lib-sieve/plugins/environment/ext-environment-common.h b/src/lib-sieve/plugins/environment/ext-environment-common.h
index eedb6ee7a0ea9dad479bfa2ada027ac90f10e1d6..9c8fec73a6494d6e4a43f24cccc1baf7074f0f2f 100644
--- a/src/lib-sieve/plugins/environment/ext-environment-common.h
+++ b/src/lib-sieve/plugins/environment/ext-environment-common.h
@@ -47,11 +47,10 @@ bool ext_environment_init(const struct sieve_extension *ext, void **context);
 void ext_environment_deinit(const struct sieve_extension *ext);
 
 /*
- * Environment item retrieval
+ * Validator context
  */
 
-const char *ext_environment_item_get_value
-	(const struct sieve_extension *ext, const char *name,
-		const struct sieve_script_env *senv);
+void ext_environment_interpreter_init
+(const struct sieve_extension *this_ext, struct sieve_interpreter *interp);
 
 #endif /* __EXT_VARIABLES_COMMON_H */
diff --git a/src/lib-sieve/plugins/environment/ext-environment.c b/src/lib-sieve/plugins/environment/ext-environment.c
index 8abc659032565417cedb29fb5edb68036f6cfd2c..e536864c43dcc212c990f039d97f417c74406fef 100644
--- a/src/lib-sieve/plugins/environment/ext-environment.c
+++ b/src/lib-sieve/plugins/environment/ext-environment.c
@@ -30,12 +30,14 @@
 
 static bool ext_environment_validator_load
 	(const struct sieve_extension *ext, struct sieve_validator *valdtr);
+static bool ext_environment_interpreter_load
+(const struct sieve_extension *ext,
+	const struct sieve_runtime_env *renv, sieve_size_t *address);
 
 const struct sieve_extension_def environment_extension = {
 	.name = "environment",
-	.load = ext_environment_init,
-	.unload = ext_environment_deinit,
 	.validator_load = ext_environment_validator_load,
+	.interpreter_load = ext_environment_interpreter_load,
 	SIEVE_EXT_DEFINE_OPERATION(tst_environment_operation)
 };
 
@@ -43,7 +45,15 @@ static bool ext_environment_validator_load
 (const struct sieve_extension *ext, struct sieve_validator *valdtr)
 {
 	sieve_validator_register_command(valdtr, ext, &tst_environment);
+	return TRUE;
+}
 
+static bool ext_environment_interpreter_load
+(const struct sieve_extension *ext,
+	const struct sieve_runtime_env *renv,
+	sieve_size_t *address ATTR_UNUSED)
+{
+	ext_environment_interpreter_init(ext, renv->interp);
 	return TRUE;
 }
 
diff --git a/src/lib-sieve/plugins/environment/sieve-ext-environment.h b/src/lib-sieve/plugins/environment/sieve-ext-environment.h
index a0c3259fe5340d97fb09ffd2ab6811cbd30c00fb..f5a52e2460bd211ed6cb75d365c75da2f741efd6 100644
--- a/src/lib-sieve/plugins/environment/sieve-ext-environment.h
+++ b/src/lib-sieve/plugins/environment/sieve-ext-environment.h
@@ -6,16 +6,43 @@
 
 #include "sieve-common.h"
 
+/*
+ * Environment extension
+ */
+
+/* FIXME: this is not suitable for future plugin support */
+
+extern const struct sieve_extension_def environment_extension;
+
+static inline const struct sieve_extension *
+sieve_ext_environment_get_extension
+(struct sieve_instance *svinst)
+{
+	return sieve_extension_register
+		(svinst, &environment_extension, FALSE);
+}
+
+bool sieve_ext_environment_is_active
+	(const struct sieve_extension *env_ext,
+		struct sieve_interpreter *interp);
+
+/*
+ * Environment item
+ */
+
 struct sieve_environment_item {
 	const char *name;
 
 	const char *value;
 	const char *(*get_value)
-		(struct sieve_instance *svinst, const struct sieve_script_env *senv);
+		(const struct sieve_runtime_env *renv);
 };
 
-void sieve_ext_environment_item_register
-	(const struct sieve_extension *ext,
+void sieve_environment_item_register
+	(const struct sieve_extension *env_ext, struct sieve_interpreter *interp,
 		const struct sieve_environment_item *item);
+const char *ext_environment_item_get_value
+	(const struct sieve_extension *env_ext,
+		const struct sieve_runtime_env *renv, const char *name);
 
 #endif
diff --git a/src/lib-sieve/plugins/environment/tst-environment.c b/src/lib-sieve/plugins/environment/tst-environment.c
index bb3fef34f42e7846c0e7e1bf0d78e78fe70e3450..68040291bcc5883301044f6c532c18369810a771 100644
--- a/src/lib-sieve/plugins/environment/tst-environment.c
+++ b/src/lib-sieve/plugins/environment/tst-environment.c
@@ -188,7 +188,7 @@ static int tst_environment_operation_execute
 	sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "environment test");
 
 	env_item = ext_environment_item_get_value
-		(this_ext, str_c(name), renv->scriptenv);
+		(this_ext, renv, str_c(name));
 
 	if ( env_item != NULL ) {
 		/* Construct value list */
diff --git a/src/lib-sieve/plugins/vnd.dovecot/Makefile.am b/src/lib-sieve/plugins/vnd.dovecot/Makefile.am
index 3c46867ff1f7b519e0efb9b24c05204041061084..65d394e41964b56fc01ac882b6c1d5fc8f01c4a8 100644
--- a/src/lib-sieve/plugins/vnd.dovecot/Makefile.am
+++ b/src/lib-sieve/plugins/vnd.dovecot/Makefile.am
@@ -1,2 +1,2 @@
-SUBDIRS = debug
+SUBDIRS = debug environment
 
diff --git a/src/lib-sieve/sieve-extensions.c b/src/lib-sieve/sieve-extensions.c
index 2f3cc8df9906954ff18c097b747ccf4ef91506c2..c910a4db940a51deaf80023fcb5583da16b7511d 100644
--- a/src/lib-sieve/sieve-extensions.c
+++ b/src/lib-sieve/sieve-extensions.c
@@ -139,6 +139,7 @@ extern const struct sieve_extension_def virustest_extension;
 extern const struct sieve_extension_def editheader_extension;
 
 extern const struct sieve_extension_def vnd_debug_extension;
+extern const struct sieve_extension_def vnd_environment_extension;
 
 const struct sieve_extension_def *sieve_extra_extensions[] = {
 	&vacation_seconds_extension, &spamtest_extension, &spamtestplus_extension,
@@ -146,7 +147,7 @@ const struct sieve_extension_def *sieve_extra_extensions[] = {
 	&mboxmetadata_extension, &servermetadata_extension,
 
 	/* vnd.dovecot. */
-	&vnd_debug_extension
+	&vnd_debug_extension, &vnd_environment_extension
 };
 
 const unsigned int sieve_extra_extensions_count =