diff --git a/sieve/tests/address-part.sieve b/sieve/tests/address-part.sieve
new file mode 100644
index 0000000000000000000000000000000000000000..cd25bf9851686ccb4480dfab383ef313fb082b79
--- /dev/null
+++ b/sieve/tests/address-part.sieve
@@ -0,0 +1,10 @@
+if address :comparator "i;ascii-casemap" :localpart "from" "STEPHAN" {
+	discard;
+
+	if address :domain :comparator "i;octet" "from" "drunksnipers.com" {
+		keep;
+	}
+	stop;
+}
+
+keep;
diff --git a/src/lib-sieve/ext-envelope.c b/src/lib-sieve/ext-envelope.c
index 66fa6e8938d8a48ef8975afca4210a4c2a8b0c4a..70698ceac607ca9bb5ac97ac385536294d39215b 100644
--- a/src/lib-sieve/ext-envelope.c
+++ b/src/lib-sieve/ext-envelope.c
@@ -154,6 +154,7 @@ static bool ext_envelope_opcode_dump
             case OPT_MATCH_TYPE:
                 break;
 			case OPT_ADDRESS_PART:
+                sieve_opr_address_part_dump(sbin, address);
 				break;
             default:
                 return FALSE;
diff --git a/src/lib-sieve/sieve-address-parts.c b/src/lib-sieve/sieve-address-parts.c
index 84ba69530180895aaadd90c8b008aad1a7fa2c02..547d5f35cc37f43bf85183256dacf1c5a00c6c3f 100644
--- a/src/lib-sieve/sieve-address-parts.c
+++ b/src/lib-sieve/sieve-address-parts.c
@@ -20,12 +20,10 @@
  * Predeclarations 
  */
  
-static struct sieve_interpreter_registry *addrp_registry = NULL;
-
 static void opr_address_part_emit
 	(struct sieve_binary *sbin, unsigned int code);
 static void opr_address_part_emit_ext
-	(struct sieve_binary *sbin, const struct sieve_extension *ext);
+	(struct sieve_binary *sbin, int ext_id);
 
 /* 
  * Comparator 'extension' 
@@ -110,13 +108,32 @@ static bool addrp_validator_load(struct sieve_validator *validator)
 	return TRUE;
 }
 
+void sieve_address_parts_link_tags
+	(struct sieve_validator *validator, 
+		struct sieve_command_registration *cmd_reg,
+		unsigned int id_code) 
+{
+	struct addrp_validator_context *ctx = get_validator_context(validator);
+	struct hash_iterate_context *itx = hash_iterate_init(ctx->address_parts);
+	void *key; 
+	void *addrp;
+	
+	while ( hash_iterate(itx, &key, &addrp) ) {
+		sieve_validator_register_tag
+			(validator, cmd_reg, ((struct sieve_address_part *) addrp)->tag, id_code); 	
+	}
+
+	hash_iterate_deinit(&itx); 	
+}
 
 /*
  * Address-part operand
  */
  
-struct sieve_operand_class address_part_class = { "address-part", NULL };
-struct sieve_operand address_part_operand = { "address-part", &address_part_class, FALSE };
+struct sieve_operand_class address_part_class = 
+	{ "address-part", NULL };
+struct sieve_operand address_part_operand = 
+	{ "address-part", &address_part_class, FALSE };
 
 /* 
  * Address-part tag 
@@ -154,38 +171,16 @@ static bool tag_address_part_validate
 	return TRUE;
 }
 
-const struct sieve_argument address_localpart_tag = 
-	{ "localpart", tag_address_part_validate, NULL };
-const struct sieve_argument address_domain_tag = 
-	{ "domain", tag_address_part_validate, NULL };
-const struct sieve_argument address_all_tag = 
-	{ "all", tag_address_part_validate, NULL };
-
-/* Address part validation */
-
-void sieve_address_parts_link_tags
-	(struct sieve_validator *validator, 
-		struct sieve_command_registration *cmd_reg,
-		unsigned int id_code) 
-{
-	sieve_validator_register_tag
-		(validator, cmd_reg, &address_localpart_tag, id_code); 	
-	sieve_validator_register_tag
-		(validator, cmd_reg, &address_domain_tag, id_code); 	
-	sieve_validator_register_tag	
-		(validator, cmd_reg, &address_all_tag, id_code); 	
-}
-
 /* Code generation */
 
-static void opr_address_parts_emit
+static void opr_address_part_emit
 	(struct sieve_binary *sbin, unsigned int code)
 { 
 	(void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_ADDRESS_PART);
 	(void) sieve_binary_emit_byte(sbin, code);
 }
 
-static void opr_address_parts_emit_ext
+static void opr_address_part_emit_ext
 	(struct sieve_binary *sbin, int ext_id)
 { 
 	unsigned char cmp_code = SIEVE_ADDRESS_PART_CUSTOM + 
@@ -228,7 +223,8 @@ const struct sieve_address_part *sieve_opr_address_part_read
 bool sieve_opr_address_part_dump(struct sieve_binary *sbin, sieve_size_t *address)
 {
 	sieve_size_t pc = *address;
-	const struct sieve_address_part *addrp = sieve_opr_address_part_read(sbin, address);
+	const struct sieve_address_part *addrp = 
+		sieve_opr_address_part_read(sbin, address);
 	
 	if ( addrp == NULL )
 		return FALSE;
@@ -243,7 +239,8 @@ static bool tag_address_part_generate
 	struct sieve_command_context *cmd ATTR_UNUSED)
 {
 	struct sieve_binary *sbin = sieve_generator_get_binary(generator);
-	struct sieve_address_part *addrp = (struct sieve_address_part *) (*arg)->context;
+	struct sieve_address_part *addrp = 
+		(struct sieve_address_part *) (*arg)->context;
 	
 	if ( addrp->extension == NULL ) {
 		if ( addrp->code < SIEVE_ADDRESS_PART_CUSTOM )
@@ -262,22 +259,32 @@ static bool tag_address_part_generate
 /* 
  * Core address-part modifiers
  */
+ 
+const struct sieve_argument address_localpart_tag = 
+	{ "localpart", tag_address_part_validate, tag_address_part_generate };
+const struct sieve_argument address_domain_tag = 
+	{ "domain", tag_address_part_validate, tag_address_part_generate };
+const struct sieve_argument address_all_tag = 
+	{ "all", tag_address_part_validate, tag_address_part_generate };
 
 const struct sieve_address_part all_address_part = {
 	"all",
+	&address_all_tag,
 	SIEVE_ADDRESS_PART_ALL,
 	NULL
 };
 
 const struct sieve_address_part local_address_part = {
 	"localpart",
+	&address_localpart_tag,
 	SIEVE_ADDRESS_PART_LOCAL,
 	NULL
 };
 
 const struct sieve_address_part domain_address_part = {
 	"domain",
-	SIEVE_ADDRESS_PART_LOCAL,
+	&address_domain_tag,
+	SIEVE_ADDRESS_PART_DOMAIN,
 	NULL
 };
 
diff --git a/src/lib-sieve/sieve-address-parts.h b/src/lib-sieve/sieve-address-parts.h
index a89b67e0dfe601ec42923d882aa172e0f82f450b..233edf1e19c10b7e3a095bd9592c80f75b35ad76 100644
--- a/src/lib-sieve/sieve-address-parts.h
+++ b/src/lib-sieve/sieve-address-parts.h
@@ -10,6 +10,7 @@ enum sieve_address_part_code {
 
 struct sieve_address_part {
 	const char *identifier;
+	const struct sieve_argument *tag;
 	
 	enum sieve_address_part_code code;
 	const struct sieve_extension *extension;
diff --git a/src/lib-sieve/sieve-code.c b/src/lib-sieve/sieve-code.c
index 2cab25d84b1c6fa057f229f52416effe7445aedf..af601d01a9091e13b9fb5d832087c61f2777e508 100644
--- a/src/lib-sieve/sieve-code.c
+++ b/src/lib-sieve/sieve-code.c
@@ -92,7 +92,7 @@ inline sieve_size_t sieve_coded_stringlist_get_current_offset(struct sieve_coded
 inline sieve_size_t sieve_operand_emit_code
 	(struct sieve_binary *sbin, int operand)
 {
-	unsigned char op = operand & SIEVE_OPERAND_CORE_MASK;
+	unsigned char op = operand;
 	
 	return sieve_binary_emit_byte(sbin, op);
 }
@@ -103,7 +103,7 @@ const struct sieve_operand *sieve_operand_read
 	unsigned int operand;
 	
 	if ( sieve_binary_read_byte(sbin, address, &operand) ) {
-		if ( operand < SIEVE_OPERAND_EXT_OFFSET ) {
+		if ( operand < SIEVE_OPERAND_CUSTOM ) {
 			if ( operand < sieve_operand_count )
 				return sieve_operands[operand];
 			else
@@ -112,7 +112,7 @@ const struct sieve_operand *sieve_operand_read
 			int ext_id = -1;
 		  const struct sieve_extension *ext = 
 		  	sieve_binary_extension_get_by_index
-		  		(sbin, operand - SIEVE_OPERAND_EXT_OFFSET, &ext_id);
+		  		(sbin, operand - SIEVE_OPERAND_CUSTOM, &ext_id);
 		  
 		  if ( ext != NULL )
 		  	return ext->operand;	
@@ -219,13 +219,16 @@ const struct sieve_operand stringlist_operand =
 /* Core operands */
 
 extern struct sieve_operand comparator_operand;
+extern struct sieve_operand address_part_operand;
 
 const struct sieve_operand *sieve_operands[] = {
 	NULL, /* SIEVE_OPERAND_OPTIONAL */
 	&number_operand,
 	&string_operand,
 	&stringlist_operand,
-	&comparator_operand
+	&comparator_operand,
+	NULL,
+	&address_part_operand
 }; 
 
 const unsigned int sieve_operand_count =
@@ -549,7 +552,7 @@ static struct sieve_coded_stringlist *opr_stringlist_read
 inline sieve_size_t sieve_operation_emit_code
 	(struct sieve_binary *sbin, int opcode)
 {
-	unsigned char op = opcode & SIEVE_OPCODE_CORE_MASK;
+	unsigned char op = opcode;
 	
 	return sieve_binary_emit_byte(sbin, op);
 }
@@ -557,7 +560,7 @@ inline sieve_size_t sieve_operation_emit_code
 inline sieve_size_t sieve_operation_emit_code_ext
 	(struct sieve_binary *sbin, int ext_id)
 {	
-	unsigned char op = SIEVE_OPCODE_EXT_OFFSET + 
+	unsigned char op = SIEVE_OPCODE_CUSTOM + 
 		sieve_binary_extension_get_index(sbin, ext_id);
 	
 	return sieve_binary_emit_byte(sbin, op);
@@ -569,7 +572,7 @@ const struct sieve_opcode *sieve_operation_read
 	unsigned int opcode;
 	
 	if ( sieve_binary_read_byte(sbin, address, &opcode) ) {
-		if ( opcode < SIEVE_OPCODE_EXT_OFFSET ) {
+		if ( opcode < SIEVE_OPCODE_CUSTOM ) {
 			if ( opcode < sieve_opcode_count )
 				return sieve_opcodes[opcode];
 			else
@@ -578,7 +581,7 @@ const struct sieve_opcode *sieve_operation_read
 			int ext_id = -1;
 			const struct sieve_extension *ext = 
 			sieve_binary_extension_get_by_index
-				(sbin, opcode - SIEVE_OPCODE_EXT_OFFSET, &ext_id);
+				(sbin, opcode - SIEVE_OPCODE_CUSTOM, &ext_id);
 		  
 			if ( ext != NULL )
 				return ext->opcode;	
diff --git a/src/lib-sieve/sieve-code.h b/src/lib-sieve/sieve-code.h
index b2df9bb8347043e99666ba968a4435ab3f9f88dc..dae9d6d41f0fb854cf08b6792a6187597ca15230 100644
--- a/src/lib-sieve/sieve-code.h
+++ b/src/lib-sieve/sieve-code.h
@@ -62,7 +62,9 @@ enum sieve_core_operand {
 	SIEVE_OPERAND_STRING_LIST,
 	SIEVE_OPERAND_COMPARATOR,
 	SIEVE_OPERAND_MATCH_TYPE,
-	SIEVE_OPERAND_ADDRESS_PART  
+	SIEVE_OPERAND_ADDRESS_PART,
+
+	SIEVE_OPERAND_CUSTOM
 };
 
 extern const struct sieve_operand *sieve_operands[];
@@ -116,7 +118,9 @@ enum sieve_core_operation {
 	SIEVE_OPCODE_HEADER, 
 	SIEVE_OPCODE_EXISTS, 
 	SIEVE_OPCODE_SIZEOVER,
-	SIEVE_OPCODE_SIZEUNDER
+	SIEVE_OPCODE_SIZEUNDER,
+	
+	SIEVE_OPCODE_CUSTOM
 };
 
 extern const struct sieve_opcode *sieve_opcodes[];
@@ -131,9 +135,4 @@ const struct sieve_opcode *sieve_operation_read
 
 /* Core operands */
 
-#define SIEVE_OPCODE_CORE_MASK  0x1F
-#define SIEVE_OPCODE_EXT_OFFSET (SIEVE_OPCODE_CORE_MASK + 1)
-#define SIEVE_OPERAND_CORE_MASK 0x1F
-#define SIEVE_OPERAND_EXT_OFFSET (SIEVE_OPCODE_CORE_MASK + 1)
-
 #endif
diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c
index 5984d9126657a47c30ecf13b2b9ecad465227edd..e870f4c241ad83ce82d817d9d33ccdb4f2a1d4d3 100644
--- a/src/lib-sieve/sieve-validator.c
+++ b/src/lib-sieve/sieve-validator.c
@@ -67,18 +67,21 @@ struct sieve_validator *sieve_validator_create(struct sieve_ast *ast, struct sie
 	
 	validator->ast = ast;	
 	sieve_ast_ref(ast);
+
+	/* Setup storage for extension contexts */		
+	array_create(&validator->ext_contexts, pool, sizeof(void *), 
+		sieve_extensions_get_count());
 		
+	/* Pre-load core language features implemented as 'extensions' */
+	(void)comparator_extension.validator_load(validator);	
+	(void)address_part_extension.validator_load(validator);	
+
 	/* Setup command registry */
 	validator->commands = hash_create
 		(pool, pool, 0, str_hash, (hash_cmp_callback_t *)strcmp);
 	sieve_validator_register_core_commands(validator);
 	sieve_validator_register_core_tests(validator);
 
-	array_create(&validator->ext_contexts, pool, sizeof(void *), 
-		sieve_extensions_get_count());
-		
-	(void)comparator_extension.validator_load(validator);	
-	(void)address_part_extension.validator_load(validator);	
 		
 	return validator;
 }
diff --git a/src/lib-sieve/tst-address.c b/src/lib-sieve/tst-address.c
index a767e73653733450440ed86f206ad8f0298c6d1b..486e9fa9625ab54ffb3112987fb7b6d64d137edc 100644
--- a/src/lib-sieve/tst-address.c
+++ b/src/lib-sieve/tst-address.c
@@ -5,6 +5,7 @@
 
 #include "sieve-comparators.h"
 #include "sieve-address-parts.h"
+
 #include "sieve-validator.h"
 #include "sieve-generator.h"
 #include "sieve-interpreter.h"
@@ -106,11 +107,14 @@ static bool tst_address_opcode_dump
         while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) {
             switch ( opt_code ) {
             case OPT_COMPARATOR:
-                sieve_opr_comparator_dump(sbin, address);
+				if ( !sieve_opr_comparator_dump(sbin, address) )
+					return FALSE;
                 break;
             case OPT_MATCH_TYPE:
                 break;
 			case OPT_ADDRESS_PART:
+				if ( !sieve_opr_address_part_dump(sbin, address) )
+					return FALSE;
 				break;			
             default:
                 return FALSE;
@@ -131,6 +135,7 @@ static bool tst_address_opcode_execute
 	struct mail *mail = sieve_interpreter_get_mail(interp);
 	
 	const struct sieve_comparator *cmp = &i_octet_comparator;
+	const struct sieve_address_part *addrp = &all_address_part;
 	unsigned int opt_code;
 	struct sieve_coded_stringlist *hdr_list;
 	struct sieve_coded_stringlist *key_list;
@@ -144,11 +149,14 @@ static bool tst_address_opcode_execute
         while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) {
             switch ( opt_code ) {
             case OPT_COMPARATOR:
-                cmp = sieve_opr_comparator_read(sbin, address);
+                if ( (cmp = sieve_opr_comparator_read(sbin, address)) == NULL )
+					return FALSE;
                 break;
             case OPT_MATCH_TYPE:
                 break;
 			case OPT_ADDRESS_PART:
+				if ( (addrp = sieve_opr_address_part_read(sbin, address)) == NULL )
+					return FALSE;
 				break;
             default:
                 return FALSE;
@@ -161,14 +169,12 @@ static bool tst_address_opcode_execute
 	/* Read header-list */
 	if ( (hdr_list=sieve_opr_stringlist_read(sbin, address)) == NULL ) {
 		t_pop();
-		printf("HDR_LIST FAILED\n");
 		return FALSE;
 	}
 	
 	/* Read key-list */
 	if ( (key_list=sieve_opr_stringlist_read(sbin, address)) == NULL ) {
 		t_pop();
-		printf("KEY_LIST FAILED\n");
 		return FALSE;
 	}