diff --git a/sieve/tests/envelope.sieve b/sieve/tests/envelope.sieve
new file mode 100644
index 0000000000000000000000000000000000000000..4bc2f978c5c13037b168dbc3a6ac0c247b92ff91
--- /dev/null
+++ b/sieve/tests/envelope.sieve
@@ -0,0 +1,14 @@
+require "envelope";
+
+if envelope :domain "to" "example.com" {
+	discard;
+	stop;
+}
+
+if envelope :domain "from" "example.com" {
+	discard;
+	stop;
+}
+
+keep;
+
diff --git a/src/lib-sieve/ext-envelope.c b/src/lib-sieve/ext-envelope.c
index 82e5c1e2b2d6ff6a7aa22537cd2e7ee698d8d772..c7ef709f0471499623bd520bcf3bf5c6b1da84f7 100644
--- a/src/lib-sieve/ext-envelope.c
+++ b/src/lib-sieve/ext-envelope.c
@@ -1,5 +1,8 @@
 #include <stdio.h>
 
+#include "lib.h"
+#include "array.h"
+
 #include "sieve-extensions.h"
 #include "sieve-commands.h"
 #include "sieve-comparators.h"
@@ -17,6 +20,8 @@ static bool ext_envelope_validator_load(struct sieve_validator *validator);
 
 static bool ext_envelope_opcode_dump
 	(struct sieve_interpreter *interp, struct sieve_binary *sbin, sieve_size_t *address);
+static bool ext_envelope_opcode_execute
+	(struct sieve_interpreter *interp, struct sieve_binary *sbin, sieve_size_t *address);
 
 static bool tst_envelope_registered
 	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg);
@@ -30,7 +35,7 @@ static bool tst_envelope_generate
 static int ext_my_id;
 
 const struct sieve_opcode envelope_opcode =
-	{ ext_envelope_opcode_dump, NULL };
+	{ ext_envelope_opcode_dump, ext_envelope_opcode_execute };
 
 const struct sieve_extension envelope_extension = { 
 	"envelope", 
@@ -65,22 +70,13 @@ static const struct sieve_command envelope_test = {
 	NULL 
 };
 
-/* Optional arguments */
-
-enum tst_envelope_optional {
-	OPT_END,
-	OPT_COMPARATOR,
-	OPT_ADDRESS_PART,
-	OPT_MATCH_TYPE
-};
-
 /* Command Registration */
 static bool tst_envelope_registered(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) 
 {
 	/* The order of these is not significant */
-	sieve_comparators_link_tag(validator, cmd_reg, OPT_COMPARATOR);
-	sieve_address_parts_link_tags(validator, cmd_reg, OPT_ADDRESS_PART);
-	sieve_match_types_link_tags(validator, cmd_reg, OPT_MATCH_TYPE);
+	sieve_comparators_link_tag(validator, cmd_reg, SIEVE_AM_OPT_COMPARATOR);
+	sieve_address_parts_link_tags(validator, cmd_reg, SIEVE_AM_OPT_ADDRESS_PART);
+	sieve_match_types_link_tags(validator, cmd_reg, SIEVE_AM_OPT_MATCH_TYPE);
 	
 	return TRUE;
 }
@@ -132,45 +128,117 @@ static bool tst_envelope_generate
 	(void)sieve_generator_emit_opcode_ext(generator, ext_my_id);
 
 	/* Generate arguments */
-    if ( !sieve_generate_arguments(generator, ctx, NULL) )
-        return FALSE;
+	if ( !sieve_generate_arguments(generator, ctx, NULL) )
+		return FALSE;
 
 	return TRUE;
 }
 
 /* 
- * Code dump
+ * Code dump 
  */
  
 static bool ext_envelope_opcode_dump
 	(struct sieve_interpreter *interp, 
 	struct sieve_binary *sbin, sieve_size_t *address)
 {
-	unsigned opt_code;
-
 	printf("ENVELOPE\n");
 
 	/* Handle any optional arguments */
-	if ( sieve_operand_optional_present(sbin, address) ) {
-		while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) {
-			switch ( opt_code ) {
-			case OPT_COMPARATOR:
-				sieve_opr_comparator_dump(interp, sbin, address);
-				break;
-			case OPT_MATCH_TYPE:
-				sieve_opr_match_type_dump(interp, sbin, address);
-				break;
-			case OPT_ADDRESS_PART:
-				sieve_opr_address_part_dump(interp, sbin, address);
-				break;
-			default:
-				return FALSE;
-			}
-		}
-	}
+	if ( !sieve_addrmatch_default_dump_optionals(interp, sbin, address) )
+		return FALSE;
 
 	return
 		sieve_opr_stringlist_dump(sbin, address) &&
 		sieve_opr_stringlist_dump(sbin, address);
 }
 
+static int ext_envelope_get_field
+(struct sieve_message_data *msgdata, const char *field, 
+	const char *const **value_r) 
+{
+	const char *value;
+	ARRAY_DEFINE(envelope_values, const char *);
+	
+ 	p_array_init(&envelope_values, pool_datastack_create(), 2);
+ 	
+	if ( strncmp(field, "from", 4) == 0 )
+		value = msgdata->return_path;
+	else if ( strncmp(field, "to", 2) == 0 )
+		value = msgdata->to_address;	
+	else if ( strncmp(field, "to", 2) == 0 )	
+		value = msgdata->auth_user;
+	
+	printf("SIZEOF: %d\n", sizeof(value));
+		
+	if ( value != NULL )
+		array_append(&envelope_values, &value, 1);
+	
+	value = NULL;
+  array_append(&envelope_values, &value, 1);
+  *value_r = array_idx(&envelope_values, 0);
+
+	return 0;
+}
+
+static bool ext_envelope_opcode_execute
+	(struct sieve_interpreter *interp, struct sieve_binary *sbin, sieve_size_t *address)
+{
+	struct sieve_message_data *msgdata = sieve_interpreter_get_msgdata(interp);
+
+	const struct sieve_comparator *cmp = &i_octet_comparator;
+	const struct sieve_match_type *mtch = &is_match_type;
+	const struct sieve_address_part *addrp = &all_address_part;
+	struct sieve_match_context *mctx;
+	struct sieve_coded_stringlist *hdr_list;
+	struct sieve_coded_stringlist *key_list;
+	string_t *hdr_item;
+	bool matched;
+	
+	printf("?? ENVELOPE\n");
+
+	if ( !sieve_addrmatch_default_get_optionals
+		(interp, sbin, address, &addrp, &mtch, &cmp) )
+		return FALSE; 
+
+	t_push();
+		
+	/* Read header-list */
+	if ( (hdr_list=sieve_opr_stringlist_read(sbin, address)) == NULL ) {
+		t_pop();
+		return FALSE;
+	}
+
+	/* Read key-list */
+	if ( (key_list=sieve_opr_stringlist_read(sbin, address)) == NULL ) {
+		t_pop();
+		return FALSE;
+	}
+	
+	/* Initialize match context */
+	mctx = sieve_match_begin(mtch, cmp, key_list);
+	
+	/* Iterate through all requested headers to match */
+	hdr_item = NULL;
+	matched = FALSE;
+	while ( !matched && sieve_coded_stringlist_next_item(hdr_list, &hdr_item) && hdr_item != NULL ) {
+		const char *const *fields;
+			
+		if ( ext_envelope_get_field(msgdata, str_c(hdr_item), &fields) >= 0 ) {	
+			
+			int i;
+			for ( i = 0; !matched && fields[i] != NULL; i++ ) {
+				if ( sieve_address_match(addrp, mctx, fields[i]) )
+					matched = TRUE;				
+			} 
+		}
+	}
+	
+	matched = sieve_match_end(mctx) || matched;
+
+	t_pop();
+	
+	sieve_interpreter_set_test_result(interp, matched);
+	
+	return TRUE;
+}
diff --git a/src/lib-sieve/sieve-address-parts.c b/src/lib-sieve/sieve-address-parts.c
index 7a5acd1e310e57dd18ba114214207e61e13b54e2..abe2881407f057464ff1c9b6564a84b834bae9db 100644
--- a/src/lib-sieve/sieve-address-parts.c
+++ b/src/lib-sieve/sieve-address-parts.c
@@ -404,6 +404,71 @@ bool sieve_address_match
 	return matched;
 }
 
+/* 
+ * Default ADDRESS-PART, MATCH-TYPE, COMPARATOR access
+ */
+ 
+bool sieve_addrmatch_default_dump_optionals
+(struct sieve_interpreter *interp, 
+	struct sieve_binary *sbin, sieve_size_t *address) 
+{
+	unsigned int opt_code;
+	
+	if ( sieve_operand_optional_present(sbin, address) ) {
+		while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) {
+			switch ( opt_code ) {
+			case SIEVE_AM_OPT_COMPARATOR:
+				if ( !sieve_opr_comparator_dump(interp, sbin, address) )
+					return FALSE;
+				break;
+			case SIEVE_AM_OPT_MATCH_TYPE:
+				if ( !sieve_opr_match_type_dump(interp, sbin, address) )
+					return FALSE;
+				break;
+			case SIEVE_AM_OPT_ADDRESS_PART:
+				if ( !sieve_opr_address_part_dump(interp, sbin, address) )
+					return FALSE;
+				break;
+			default:
+				return FALSE;
+			}
+		}
+	}
+	
+	return TRUE;
+}
+
+bool sieve_addrmatch_default_get_optionals
+(struct sieve_interpreter *interp, struct sieve_binary *sbin, 
+	sieve_size_t *address, const struct sieve_address_part **addrp, 
+	const struct sieve_match_type **mtch, const struct sieve_comparator **cmp) 
+{
+	unsigned int opt_code;
+	
+	if ( sieve_operand_optional_present(sbin, address) ) {
+		while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) {
+			switch ( opt_code ) {
+			case SIEVE_AM_OPT_COMPARATOR:
+				if ( (*cmp = sieve_opr_comparator_read(interp, sbin, address)) == NULL )
+					return FALSE;
+				break;
+			case SIEVE_AM_OPT_MATCH_TYPE:
+				if ( (*mtch = sieve_opr_match_type_read(interp, sbin, address)) == NULL )
+					return FALSE;
+				break;
+			case SIEVE_AM_OPT_ADDRESS_PART:
+				if ( (*addrp = sieve_opr_address_part_read(interp, sbin, address)) == NULL )
+					return FALSE;
+				break;
+			default:
+				return FALSE;
+			}
+		}
+	}
+	
+	return TRUE;
+}
+
 /* 
  * Core address-part modifiers
  */
diff --git a/src/lib-sieve/sieve-address-parts.h b/src/lib-sieve/sieve-address-parts.h
index 5fe765bfd1824d2f0b793496f78576e42dac80d1..728023138c965d2ca91d5d5c609190ae5b960782 100644
--- a/src/lib-sieve/sieve-address-parts.h
+++ b/src/lib-sieve/sieve-address-parts.h
@@ -67,8 +67,25 @@ bool sieve_opr_address_part_dump
 	(struct sieve_interpreter *interpreter,
 		struct sieve_binary *sbin, sieve_size_t *address);
 
+/* Match utility */
+
 bool sieve_address_match
 (const struct sieve_address_part *addrp, struct sieve_match_context *mctx,
     const char *data);
 
+enum sieve_addrmatch_opt_operand {
+	SIEVE_AM_OPT_END,
+	SIEVE_AM_OPT_COMPARATOR,
+	SIEVE_AM_OPT_ADDRESS_PART,
+	SIEVE_AM_OPT_MATCH_TYPE
+};
+
+bool sieve_addrmatch_default_dump_optionals
+(struct sieve_interpreter *interp, 
+	struct sieve_binary *sbin, sieve_size_t *address);
+bool sieve_addrmatch_default_get_optionals
+	(struct sieve_interpreter *interp, struct sieve_binary *sbin, 
+		sieve_size_t *address, const struct sieve_address_part **addp, 
+		const struct sieve_match_type **mtch, const struct sieve_comparator **cmp);
+
 #endif /* __SIEVE_ADDRESS_PARTS_H */
diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h
index e7b10fcbb8b81e66b0de98946c7afed1b28f2d21..beb591927f479b596e7eb89ceb9f757010b750a9 100644
--- a/src/lib-sieve/sieve.h
+++ b/src/lib-sieve/sieve.h
@@ -9,7 +9,7 @@ struct sieve_binary;
 struct sieve_message_data {
 	struct mail *mail;
 	const char *return_path;
-	const char *rcpt_address;
+	const char *to_address;
 	const char *auth_user;
 };	
 
diff --git a/src/lib-sieve/tst-address.c b/src/lib-sieve/tst-address.c
index d0aef5d484d7017abc06bdb09de9d7b853896d40..044acd1420a93eb88b411d85dfe9810237d81db3 100644
--- a/src/lib-sieve/tst-address.c
+++ b/src/lib-sieve/tst-address.c
@@ -46,24 +46,15 @@ const struct sieve_command tst_address = {
 	NULL 
 };
 
-/* Optional arguments */
-
-enum tst_address_optional {
-	OPT_END,
-	OPT_COMPARATOR,
-	OPT_ADDRESS_PART,
-	OPT_MATCH_TYPE
-};
-
 /* Test registration */
 
 static bool tst_address_registered
 	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) 
 {
 	/* The order of these is not significant */
-	sieve_comparators_link_tag(validator, cmd_reg, OPT_COMPARATOR );
-	sieve_address_parts_link_tags(validator, cmd_reg, OPT_ADDRESS_PART);
-	sieve_match_types_link_tags(validator, cmd_reg, OPT_MATCH_TYPE);
+	sieve_comparators_link_tag(validator, cmd_reg, SIEVE_AM_OPT_COMPARATOR );
+	sieve_address_parts_link_tags(validator, cmd_reg, SIEVE_AM_OPT_ADDRESS_PART);
+	sieve_match_types_link_tags(validator, cmd_reg, SIEVE_AM_OPT_MATCH_TYPE);
 
 	return TRUE;
 }
@@ -115,31 +106,11 @@ static bool tst_address_opcode_dump
 	(struct sieve_interpreter *interp, 
 	struct sieve_binary *sbin, sieve_size_t *address)
 {
-	unsigned int opt_code;
-
 	printf("ADDRESS\n");
 
-	/* Handle any optional arguments */
-	if ( sieve_operand_optional_present(sbin, address) ) {
-		while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) {
-			switch ( opt_code ) {
-			case OPT_COMPARATOR:
-				if ( !sieve_opr_comparator_dump(interp, sbin, address) )
-					return FALSE;
-				break;
-			case OPT_MATCH_TYPE:
-				if ( !sieve_opr_match_type_dump(interp, sbin, address) )
-					return FALSE;
-				break;
-			case OPT_ADDRESS_PART:
-				if ( !sieve_opr_address_part_dump(interp, sbin, address) )
-					return FALSE;
-				break;			
-			default:
-				return FALSE;
-			}
-		}
-	}
+	//* Handle any optional arguments */
+	if ( !sieve_addrmatch_default_dump_optionals(interp, sbin, address) )
+		return FALSE;
 
 	return
 		sieve_opr_stringlist_dump(sbin, address) &&
@@ -156,7 +127,6 @@ static bool tst_address_opcode_execute
 	const struct sieve_comparator *cmp = &i_octet_comparator;
 	const struct sieve_match_type *mtch = &is_match_type;
 	const struct sieve_address_part *addrp = &all_address_part;
-	unsigned int opt_code;
 	struct sieve_match_context *mctx;
 	struct sieve_coded_stringlist *hdr_list;
 	struct sieve_coded_stringlist *key_list;
@@ -165,27 +135,9 @@ static bool tst_address_opcode_execute
 	
 	printf("?? ADDRESS\n");
 
-	/* Handle any optional arguments */
-	if ( sieve_operand_optional_present(sbin, address) ) {
-		while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) {
-			switch ( opt_code ) {
-			case OPT_COMPARATOR:
-				if ( (cmp = sieve_opr_comparator_read(interp, sbin, address)) == NULL )
-					return FALSE;
-				break;
-			case OPT_MATCH_TYPE:
-				if ( (mtch = sieve_opr_match_type_read(interp, sbin, address)) == NULL )
-					return FALSE;
-				break;
-			case OPT_ADDRESS_PART:
-				if ( (addrp = sieve_opr_address_part_read(interp, sbin, address)) == NULL )
-					return FALSE;
-				break;
-			default:
-				return FALSE;
-			}
-		}
-	}
+	if ( !sieve_addrmatch_default_get_optionals
+		(interp, sbin, address, &addrp, &mtch, &cmp) )
+		return FALSE; 
 
 	t_push();
 		
diff --git a/src/sieve-bin/sieve_test.c b/src/sieve-bin/sieve_test.c
index 83498fe5bfb9e11e928f116a53d0131e34d12381..c6ed48befc1df3656aebd09e0f2646f10aa60465 100644
--- a/src/sieve-bin/sieve_test.c
+++ b/src/sieve-bin/sieve_test.c
@@ -237,7 +237,7 @@ int main(int argc, char **argv)
 
 	msgdata.mail = mail;
 	msgdata.return_path = "nico@example.com";
-	msgdata.rcpt_address = "sirius+sieve@rename-it.nl";
+	msgdata.to_address = "sirius+sieve@rename-it.nl";
 	msgdata.auth_user = "stephan";
 	sieve_test(sbin, &msgdata);