diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index 614fc5f21f72ce5da81cb0d31271b5facbc3527e..baffba9051873140f15c0ad85380d5d61c1d5360 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -1402,22 +1402,6 @@ sieve_result_implicit_keep_finalize(struct sieve_result_execution *rexec,
 	return rexec->keep_status;
 }
 
-int sieve_result_implicit_keep(struct sieve_result_execution *rexec,
-			       struct sieve_error_handler *ehandler,
-			       bool success)
-{
-	int ret;
-
-	rexec->ehandler = ehandler;
-
-	sieve_result_implicit_keep_execute(rexec, success);
-	ret = sieve_result_implicit_keep_finalize(rexec, success);
-
-	sieve_action_execution_post(rexec);
-
-	return ret;
-}
-
 bool sieve_result_executed(struct sieve_result *result)
 {
 	return result->executed;
@@ -1539,15 +1523,38 @@ sieve_result_transaction_finish(struct sieve_result_execution *rexec, bool last,
 	sieve_action_execution_post(rexec);
 }
 
-int sieve_result_execute(struct sieve_result_execution *rexec,
+static void
+sieve_result_execute_update_status(struct sieve_result_execution *rexec,
+				   int status)
+{
+	switch (status) {
+	case SIEVE_EXEC_OK:
+		break;
+	case SIEVE_EXEC_TEMP_FAILURE:
+		rexec->status = status;
+		break;
+	case SIEVE_EXEC_BIN_CORRUPT:
+		i_unreached();
+	case SIEVE_EXEC_FAILURE:
+	case SIEVE_EXEC_KEEP_FAILED:
+		if (rexec->status == SIEVE_EXEC_OK)
+			rexec->status = status;
+		break;
+	case SIEVE_EXEC_RESOURCE_LIMIT:
+		if (rexec->status != SIEVE_EXEC_TEMP_FAILURE)
+			rexec->status = status;
+		break;
+	}
+}
+
+int sieve_result_execute(struct sieve_result_execution *rexec, int status,
 			 bool last, struct sieve_error_handler *ehandler,
 			 bool *keep_r)
 {
 	const struct sieve_action_exec_env *aenv = &rexec->action_env;
 	struct sieve_result *result = aenv->result;
-	int status = SIEVE_EXEC_OK, result_status;
 	struct sieve_result_action *actions_head, *actions_tail;
-	int ret;
+	int result_status, ret;
 
 	if (keep_r != NULL)
 		*keep_r = FALSE;
@@ -1562,24 +1569,31 @@ int sieve_result_execute(struct sieve_result_execution *rexec,
 	actions_head = (result->last_attempted_action == NULL ?
 			result->actions_head :
 			result->last_attempted_action->next);
+	actions_tail = actions_head;
 	result->last_attempted_action = result->actions_tail;
 
-	/* Transaction start */
+	if (status != SIEVE_EXEC_OK) {
+		sieve_result_execute_update_status(rexec, status);
+	} else if (rexec->status == SIEVE_EXEC_OK) {
+		/* Transaction start */
 
-	status = sieve_result_transaction_start(rexec, actions_head,
-						&actions_tail);
+		status = sieve_result_transaction_start(rexec, actions_head,
+							&actions_tail);
 
-	/* Transaction execute */
+		/* Transaction execute */
 
-	if (status == SIEVE_EXEC_OK)
-		status = sieve_result_transaction_execute(rexec, actions_head);
-	rexec->status = status;
+		if (status == SIEVE_EXEC_OK) {
+			status = sieve_result_transaction_execute(rexec,
+								  actions_head);
+		}
+		sieve_result_execute_update_status(rexec, status);
+	}
 
 	/* Transaction commit/rollback */
 
 	status = sieve_result_transaction_commit_or_rollback(
 		rexec, status, actions_head, actions_tail);
-	rexec->status = status;
+	sieve_result_execute_update_status(rexec, status);
 
 	/* Perform implicit keep if necessary */
 
@@ -1621,6 +1635,8 @@ int sieve_result_execute(struct sieve_result_execution *rexec,
 	sieve_action_execution_post(rexec);
 	rexec->ehandler = NULL;
 
+	rexec->status = result_status;
+
 	/* Merge explicit keep status into implicit keep for the next execution
 	   round.
 	 */
diff --git a/src/lib-sieve/sieve-result.h b/src/lib-sieve/sieve-result.h
index 390b7613121a7dccef66d66c7c3ebab87365afd6..fa856e7977e6bda61b741ca2bd9fb5958943fc84 100644
--- a/src/lib-sieve/sieve-result.h
+++ b/src/lib-sieve/sieve-result.h
@@ -110,11 +110,7 @@ struct sieve_result_execution *
 sieve_result_execution_create(struct sieve_result *result, pool_t pool);
 void sieve_result_execution_destroy(struct sieve_result_execution **_rexec);
 
-int sieve_result_implicit_keep(struct sieve_result_execution *rexec,
-			       struct sieve_error_handler *ehandler,
-			       bool success);
-
-int sieve_result_execute(struct sieve_result_execution *rexec,
+int sieve_result_execute(struct sieve_result_execution *rexec, int status,
 			 bool last, struct sieve_error_handler *ehandler,
 			 bool *keep_r);
 
diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c
index dde0d4bfd6a50c729a826fb5670a1df16a2e93f5..38a7f5bd26fec24f38399502d571fc7c1faf7c58 100644
--- a/src/lib-sieve/sieve.c
+++ b/src/lib-sieve/sieve.c
@@ -664,24 +664,7 @@ int sieve_execute(struct sieve_binary *sbin,
 	   caller. In that case no implicit keep is attempted, because the
 	   situation may be resolved.
 	 */
-	if (ret > 0) {
-		/* Execute result */
-		ret = sieve_result_execute(rexec, TRUE, action_ehandler, NULL);
-	} else if (ret == SIEVE_EXEC_FAILURE) {
-		/* Perform implicit keep if script failed with a normal runtime
-		   error
-		 */
-		switch (sieve_result_implicit_keep(rexec, action_ehandler,
-						   FALSE)) {
-		case SIEVE_EXEC_OK:
-			break;
-		case SIEVE_EXEC_TEMP_FAILURE:
-			ret = SIEVE_EXEC_TEMP_FAILURE;
-			break;
-		default:
-			ret = SIEVE_EXEC_KEEP_FAILED;
-		}
-	}
+	ret = sieve_result_execute(rexec, ret, TRUE, action_ehandler, NULL);
 
 	sieve_result_execution_destroy(&rexec);
 
@@ -794,15 +777,10 @@ sieve_multiscript_execute(struct sieve_multiscript *mscript,
 	mscript->exec_env.flags = flags;
 
 	if (mscript->status > 0) {
-		mscript->status = sieve_result_execute(mscript->rexec, FALSE,
+		mscript->status = sieve_result_execute(mscript->rexec,
+						       SIEVE_EXEC_OK, FALSE,
 						       ehandler,
 						       &mscript->keep);
-	} else {
-		if (sieve_result_implicit_keep(mscript->rexec, ehandler,
-					       FALSE) <= 0)
-			mscript->status = SIEVE_EXEC_KEEP_FAILED;
-		else
-			mscript->keep = TRUE;
 	}
 }
 
@@ -897,35 +875,31 @@ int sieve_multiscript_finish(struct sieve_multiscript **_mscript,
 		return SIEVE_EXEC_OK;
 	*_mscript = NULL;
 
+	switch (status) {
+	case SIEVE_EXEC_OK:
+		status = mscript->status;
+		break;
+	case SIEVE_EXEC_TEMP_FAILURE:
+		break;
+	case SIEVE_EXEC_BIN_CORRUPT:
+	case SIEVE_EXEC_FAILURE:
+	case SIEVE_EXEC_KEEP_FAILED:
+	case SIEVE_EXEC_RESOURCE_LIMIT:
+		if (mscript->status == SIEVE_EXEC_TEMP_FAILURE)
+			status = mscript->status;
+		break;
+	}
+
 	mscript->exec_env.flags = flags;
 	sieve_result_set_keep_action(mscript->result, NULL, &act_store);
 
-	if (mscript->active) {
-		if (mscript->teststream != NULL) {
-			if (status != SIEVE_EXEC_TEMP_FAILURE)
-				mscript->keep = TRUE;
-		} else if (status != SIEVE_EXEC_TEMP_FAILURE ||
-			   sieve_result_executed(mscript->result)) {
-			switch (sieve_result_implicit_keep(
-				mscript->rexec, action_ehandler, TRUE)) {
-			case SIEVE_EXEC_OK:
-				mscript->keep = TRUE;
-				break;
-			case SIEVE_EXEC_TEMP_FAILURE:
-				if (!sieve_result_executed(mscript->result)) {
-					status = SIEVE_EXEC_TEMP_FAILURE;
-					break;
-				}
-				/* fall through */
-			default:
-				status = SIEVE_EXEC_KEEP_FAILED;
-			}
-		}
-	}
-
-	if (status != SIEVE_EXEC_TEMP_FAILURE) {
-		sieve_result_finish(mscript->rexec, action_ehandler,
-				    (status == SIEVE_EXEC_OK));
+	mscript->keep = FALSE;
+	if (mscript->teststream != NULL)
+		mscript->keep = TRUE;
+	else {
+		status = sieve_result_execute(
+			mscript->rexec, status, TRUE, action_ehandler,
+			&mscript->keep);
 	}
 
 	/* Cleanup */
diff --git a/src/sieve-tools/sieve-test.c b/src/sieve-tools/sieve-test.c
index 08059cb7c1f9ec7d4f70d19a9dd69f6bcb1c93e7..5a4235c099a9861643b3a8a94fd4ff569a246a04 100644
--- a/src/sieve-tools/sieve-test.c
+++ b/src/sieve-tools/sieve-test.c
@@ -374,7 +374,6 @@ int main(int argc, char **argv)
 			unsigned int i, count;
 			struct sieve_multiscript *mscript;
 			bool more = TRUE;
-			int result;
 
 			if (execute)
 				mscript = sieve_multiscript_start_execute(
@@ -440,10 +439,8 @@ int main(int argc, char **argv)
 					exflags);
 			}
 
-			result = sieve_multiscript_finish(
-				&mscript, ehandler, exflags, ret);
-
-			ret = (ret > 0 ? result : ret);
+			ret = sieve_multiscript_finish(&mscript, ehandler,
+						       exflags, ret);
 		}
 
 		/* Run */
diff --git a/src/testsuite/testsuite-result.c b/src/testsuite/testsuite-result.c
index 927b88492c92fcff1cc2e86fc3f3d5f5ce0b62ca..51be3ff35fb06e6623221d82ed41d8fdd82a9b77 100644
--- a/src/testsuite/testsuite-result.c
+++ b/src/testsuite/testsuite-result.c
@@ -100,7 +100,7 @@ bool testsuite_result_execute(const struct sieve_runtime_env *renv)
 	}
 
 	/* Execute the result */
-	ret = sieve_result_execute(_testsuite_rexec, TRUE,
+	ret = sieve_result_execute(_testsuite_rexec, SIEVE_EXEC_OK, TRUE,
 				   testsuite_log_ehandler, NULL);
 
 	return (ret > 0);