diff --git a/Makefile.am b/Makefile.am
index 7e5a978c0a3d7786a52d2e29b1b5992246029d54..b46d3673e3ba8a8828be60b01cff011ed03594ba 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -38,7 +38,7 @@ test_cases = \
 	tests/extensions/variables/errors.svtest \
 	tests/extensions/include/variables.svtest \
 	tests/extensions/imapflags/basic.svtest \
-	tests/extensions/imapflags/rfc.svtest \
+	tests/extensions/imapflags/hasflag.svtest \
 	tests/compile/compile.svtest \
 	tests/compile/compile-examples.svtest \
 	tests/compile/errors.svtest
diff --git a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
index c8bc024f6fb9c9cb7b058ecde964ee50094f80fe..708ceedbf4325cf7b9ace6ac806df66f9b590702 100644
--- a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+++ b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
@@ -58,12 +58,22 @@ bool ext_imapflags_command_validate
 				
 		if ( sieve_ast_argument_type(arg) != SAAT_STRING ) 
 		{
-			sieve_command_validate_error(validator, cmd, 
-				"if a second argument is specified for the %s %s, the first "
-				"must be a string (variable name), but %s was found",
-				cmd->command->identifier, sieve_command_type_name(cmd->command), 
-				sieve_ast_argument_name(arg));
-			return FALSE; 
+			if ( cmd->command == &tst_hasflag ) {
+				if ( sieve_ast_argument_type(arg) != SAAT_STRING_LIST ) {
+					sieve_command_validate_error(validator, cmd, 
+						"if a second argument is specified for the hasflag, the first "
+						"must be a string-list (variable-list), but %s was found",
+						sieve_ast_argument_name(arg));
+					return FALSE;
+				}
+			} else {
+				sieve_command_validate_error(validator, cmd, 
+					"if a second argument is specified for the %s %s, the first "
+					"must be a string (variable name), but %s was found",
+					cmd->command->identifier, sieve_command_type_name(cmd->command), 
+					sieve_ast_argument_name(arg));
+				return FALSE; 
+			}
 		}
 		
 		/* Then, check whether the second argument is permitted */
@@ -76,7 +86,8 @@ bool ext_imapflags_command_validate
 			return FALSE;
 		}		
 		
-		if ( !sieve_variable_argument_activate(validator, cmd, arg, TRUE) )
+		if ( !sieve_variable_argument_activate(validator, cmd, arg, 
+			cmd->command != &tst_hasflag ) )
 			return FALSE;
 		
 		if ( sieve_ast_argument_type(arg2) != SAAT_STRING && 
@@ -464,16 +475,14 @@ const char *ext_imapflags_get_flags_string
 
 void ext_imapflags_get_flags_init
 (struct ext_imapflags_iter *iter, const struct sieve_runtime_env *renv,
-	struct sieve_variable_storage *storage, unsigned int var_index)
+	string_t *flags_list)
 {
 	string_t *cur_flags;
 	
-	if ( storage != NULL ) {
-		string_t *raw_flags;
+	if ( flags_list != NULL ) {
 		cur_flags = t_str_new(256);
 		
-		sieve_variable_get_modifiable(storage, var_index, &raw_flags);
-		flags_list_set_flags(cur_flags, raw_flags);
+		flags_list_set_flags(cur_flags, flags_list);
 	}
 	else
 		cur_flags = _get_flags_string(renv->result);
diff --git a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.h b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
index c2f6ff6109a84879245b189d11bc9c0cc83264f5..b50d7fb82669526fd0fbaeae40a9b47f9187d59d 100644
--- a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+++ b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
@@ -79,7 +79,7 @@ void ext_imapflags_remove_flags
 
 void ext_imapflags_get_flags_init
 	(struct ext_imapflags_iter *iter, const struct sieve_runtime_env *renv,
-		struct sieve_variable_storage *storage, unsigned int var_index);
+		string_t *flags_list);
 void ext_imapflags_get_implicit_flags_init
 	(struct ext_imapflags_iter *iter, struct sieve_result *result);
 
diff --git a/src/lib-sieve/plugins/imapflags/tst-hasflag.c b/src/lib-sieve/plugins/imapflags/tst-hasflag.c
index 66ebe188ea3c68c777dc338aa8a07769bda16ba3..cf1115149d54e108898908ef52bd6c6e531c874d 100644
--- a/src/lib-sieve/plugins/imapflags/tst-hasflag.c
+++ b/src/lib-sieve/plugins/imapflags/tst-hasflag.c
@@ -64,9 +64,7 @@ const struct sieve_operation hasflag_operation = {
  */
 
 enum tst_hasflag_optional {	
-	OPT_END,
-	OPT_COMPARATOR,
-	OPT_MATCH_TYPE
+	OPT_VARIABLES = SIEVE_MATCH_OPT_LAST,
 };
 
 /* 
@@ -78,8 +76,8 @@ static bool tst_hasflag_registered
 	struct sieve_command_registration *cmd_reg) 
 {
 	/* The order of these is not significant */
-	sieve_comparators_link_tag(validator, cmd_reg, OPT_COMPARATOR);
-	sieve_match_types_link_tags(validator, cmd_reg, OPT_MATCH_TYPE);
+	sieve_comparators_link_tag(validator, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR);
+	sieve_match_types_link_tags(validator, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
 
 	return TRUE;
 }
@@ -91,13 +89,21 @@ static bool tst_hasflag_registered
 static bool tst_hasflag_validate
 	(struct sieve_validator *validator,	struct sieve_command_context *tst)
 {
+	struct sieve_ast_argument *vars = tst->first_positional;
+	struct sieve_ast_argument *keys = sieve_ast_argument_next(vars);
+		
 	if ( !ext_imapflags_command_validate(validator, tst) )
 		return FALSE;
-		
-	/* Validate the key argument to a specified match type */
 	
-	return sieve_match_type_validate(validator, tst, 
-		sieve_ast_argument_next(tst->first_positional));
+	if ( keys == NULL ) {
+		keys = vars;
+		vars = NULL;
+	} else {
+		vars->arg_id_code = OPT_VARIABLES;
+	}
+	
+	/* Validate the key argument to a specified match type */
+	return sieve_match_type_validate(validator, tst, keys);
 }
 
 /*
@@ -130,13 +136,23 @@ static bool tst_hasflag_operation_dump
 	sieve_code_descend(denv);
 
 	/* Handle any optional arguments */
-	if ( !sieve_match_dump_optional_operands(denv, address, &opt_code) )
-		return FALSE;
+	do {
+		if ( !sieve_match_dump_optional_operands(denv, address, &opt_code) )
+			return FALSE;
 
-	if ( opt_code != SIEVE_MATCH_OPT_END )
-		return FALSE;
-
-	return ext_imapflags_command_operands_dump(denv, address); 
+		switch ( opt_code ) {
+		case SIEVE_MATCH_OPT_END:
+			break;
+		case OPT_VARIABLES:
+			sieve_opr_stringlist_dump(denv, address);
+			break;
+		default:
+			return FALSE;
+		}
+	} while ( opt_code != SIEVE_MATCH_OPT_END );
+			
+	return 
+			sieve_opr_stringlist_dump(denv, address);
 }
 
 /*
@@ -177,15 +193,13 @@ static int tst_hasflag_operation_execute
 (const struct sieve_operation *op ATTR_UNUSED,
 	const struct sieve_runtime_env *renv, sieve_size_t *address)
 {
-	int ret = SIEVE_EXEC_OK;
-	int mret;
+	int ret, mret;
+	bool result = TRUE;
 	int opt_code = 0;
 	const struct sieve_comparator *cmp = &i_ascii_casemap_comparator;
 	const struct sieve_match_type *mtch = &is_match_type;
 	struct sieve_match_context *mctx;
-	struct sieve_coded_stringlist *flag_list;
-	struct sieve_variable_storage *storage;
-	unsigned int var_index;
+	struct sieve_coded_stringlist *flag_list, *variables_list = NULL;
 	struct ext_imapflags_iter iter;
 	const char *flag;
 	bool matched;
@@ -195,21 +209,33 @@ static int tst_hasflag_operation_execute
 	 */
 
 	/* Handle match-type and comparator operands */
-	if ( (ret=sieve_match_read_optional_operands
-		(renv, address, &opt_code, &cmp, &mtch)) <= 0 )
-		return ret;
+	do {
+		if ( (ret=sieve_match_read_optional_operands
+			(renv, address, &opt_code, &cmp, &mtch)) <= 0 )
+			return ret;
 	
-	/* Check whether we neatly finished the list of optional operands*/
-	if ( opt_code != SIEVE_MATCH_OPT_END) {
-		sieve_runtime_trace_error(renv, "invalid optional operand");
+		/* Check whether we neatly finished the list of optional operands*/
+		switch ( opt_code ) { 
+		case SIEVE_MATCH_OPT_END:
+			break;
+		case OPT_VARIABLES:
+			if ( (variables_list=sieve_opr_stringlist_read(renv, address)) == NULL ) {
+					sieve_runtime_trace_error(renv, "invalid variables-list operand");
+				return SIEVE_EXEC_BIN_CORRUPT;
+			}
+			break;
+		default:
+			sieve_runtime_trace_error(renv, "invalid optional operand");
+			return SIEVE_EXEC_BIN_CORRUPT;
+		}
+	} while ( opt_code != SIEVE_MATCH_OPT_END );
+		
+	/* Read flag list */
+	if ( (flag_list=sieve_opr_stringlist_read(renv, address)) == NULL ) {
+		sieve_runtime_trace_error(renv, "invalid flag-list operand");
 		return SIEVE_EXEC_BIN_CORRUPT;
 	}
 
-	/* Read the common imap4flags command operands [variable] <flag-list> */
-	if ( (ret=ext_imapflags_command_operands_read
-		(renv, address, &flag_list, &storage, &var_index)) <= 0 )
-		return ret;
-
 	/*
 	 * Perform operation
 	 */
@@ -220,29 +246,51 @@ static int tst_hasflag_operation_execute
 	mctx = sieve_match_begin
 		(renv->interp, mtch, cmp, &_flag_extractor, flag_list); 	
 
-	ext_imapflags_get_flags_init(&iter, renv, storage, var_index);
-	
-	while ( !matched && (flag=ext_imapflags_iter_get_flag(&iter)) != NULL ) {
-		if ( (mret=sieve_match_value(mctx, flag, strlen(flag))) < 0 ) {
-			sieve_runtime_trace_error(renv, "invalid string list item");
-			ret = SIEVE_EXEC_BIN_CORRUPT;
-			break;
-		}
+	matched = FALSE;
 
-		matched = ( mret > 0 ); 	
+	if ( variables_list != NULL ) {
+		string_t *var_item = NULL;
+		
+		/* Iterate through all requested variables to match */
+		while ( result && !matched && 
+			(result=sieve_coded_stringlist_next_item(variables_list, &var_item)) 
+			&& var_item != NULL ) {
+		
+			ext_imapflags_get_flags_init(&iter, renv, var_item);	
+			while ( !matched && (flag=ext_imapflags_iter_get_flag(&iter)) != NULL ) {
+				if ( (mret=sieve_match_value(mctx, flag, strlen(flag))) < 0 ) {
+					result = FALSE;
+					break;
+				}
+
+				matched = ( mret > 0 ); 	
+			}
+		}
+	} else {
+		ext_imapflags_get_flags_init(&iter, renv, NULL);	
+		while ( !matched && (flag=ext_imapflags_iter_get_flag(&iter)) != NULL ) {
+			if ( (mret=sieve_match_value(mctx, flag, strlen(flag))) < 0 ) {
+				result = FALSE;
+				break;
+			}
+
+			matched = ( mret > 0 ); 	
+		}
 	}
 
 	if ( (mret=sieve_match_end(mctx)) < 0 ) {
-		sieve_runtime_trace_error(renv, "invalid string list item");
-		ret = SIEVE_EXEC_BIN_CORRUPT;
+		result = FALSE;
 	} else
 		matched = ( mret > 0 || matched ); 	
 	
 	/* Assign test result */
-	if ( ret == SIEVE_EXEC_OK )
+	if ( result ) {
 		sieve_interpreter_set_test_result(renv->interp, matched);
+		return SIEVE_EXEC_OK;
+	}
 	
-	return ret;
+	sieve_runtime_trace_error(renv, "invalid string list item");
+	return SIEVE_EXEC_BIN_CORRUPT;
 }
 
 
diff --git a/src/lib-sieve/plugins/variables/ext-variables-arguments.c b/src/lib-sieve/plugins/variables/ext-variables-arguments.c
index 3f8382650c00b470b06d214e2565de992710e12e..afc80054de3df48ebcdd6239fc46f3112f7b428a 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-arguments.c
+++ b/src/lib-sieve/plugins/variables/ext-variables-arguments.c
@@ -49,7 +49,7 @@ static struct sieve_ast_argument *ext_variables_variable_argument_create
 	return arg;
 }
 
-bool sieve_variable_argument_activate
+static bool _sieve_variable_argument_activate
 (struct sieve_validator *validator, struct sieve_command_context *cmd, 
 	struct sieve_ast_argument *arg, bool assignment)
 {
@@ -113,6 +113,37 @@ bool sieve_variable_argument_activate
 	return result;
 }
 
+bool sieve_variable_argument_activate
+(struct sieve_validator *validator, struct sieve_command_context *cmd, 
+	struct sieve_ast_argument *arg, bool assignment)
+{
+	if ( sieve_ast_argument_type(arg) == SAAT_STRING ) {
+		/* Single string */
+		return _sieve_variable_argument_activate(validator, cmd, arg, assignment);
+		
+	} else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) {
+		/* String list */
+		struct sieve_ast_argument *stritem;
+		
+		i_assert ( !assignment );
+		
+		stritem = sieve_ast_strlist_first(arg);
+		while ( stritem != NULL ) {
+			if ( !_sieve_variable_argument_activate
+				(validator, cmd, stritem, assignment) )
+				return FALSE;
+			
+			stritem = sieve_ast_strlist_next(stritem);
+		}
+		
+		arg->argument = &string_list_argument;
+		
+		return TRUE;
+	} 
+	
+	return FALSE;
+}
+
 static bool arg_variable_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, 
 	struct sieve_command_context *context ATTR_UNUSED)
diff --git a/src/lib-sieve/sieve-generator.c b/src/lib-sieve/sieve-generator.c
index 12b0d84dc6bf24f58e4af2aa41a1113be16a531f..994110b1feb55796889eef1ba06be80f39fcff55 100644
--- a/src/lib-sieve/sieve-generator.c
+++ b/src/lib-sieve/sieve-generator.c
@@ -225,7 +225,7 @@ bool sieve_generate_arguments(const struct sieve_codegen_env *cgenv,
 			else {
 				/* Mark start of optional operands with 0 operand identifier */
 				sieve_binary_emit_byte(cgenv->sbin, SIEVE_OPERAND_OPTIONAL);
-				
+								
 				/* Emit argument id for optional operand */
 				sieve_binary_emit_byte(cgenv->sbin, (unsigned char) arg->arg_id_code);
 
diff --git a/tests/extensions/imapflags/rfc.svtest b/tests/extensions/imapflags/hasflag.svtest
similarity index 80%
rename from tests/extensions/imapflags/rfc.svtest
rename to tests/extensions/imapflags/hasflag.svtest
index 059d3c9d069c7e78ee1815231806d4aca276d80e..07596496df9f0ca45a23c21951bb6d5276656a65 100644
--- a/tests/extensions/imapflags/rfc.svtest
+++ b/tests/extensions/imapflags/hasflag.svtest
@@ -5,11 +5,36 @@ require "relational";
 require "variables";
 require "comparator-i;ascii-numeric";
 
+/*
+ * Generic tests
+ */
+
+test "Ignoring \"\"" {
+	setflag "";
+
+	if hasflag "" {
+		test_fail "hasflag fails to ignore empty string";
+	}
+}
+
+/*
+ * Variables
+ */
+
+test "Multiple variables" {
+	setflag "A" "Aflag";
+	setflag "B" "Bflag";
+	setflag "C" "Cflag";
+
+	if not hasflag ["a", "b", "c"] ["Bflag"] {
+		test_fail "hasflag failed to match multiple flags variables";
+	}
+}
+
 /*
  * RFC examples
  */ 
 
-
 test "RFC hasflag example - :is" {
 	setflag "A B";