diff --git a/include/class.filter.php b/include/class.filter.php
index c29df8dc579a52aa071fe6c806521676bb2c5b92..bfd92285f33829e2093b6c9263ad6616cd53fd0d 100644
--- a/include/class.filter.php
+++ b/include/class.filter.php
@@ -530,7 +530,7 @@ class Filter {
         self::save_rules($id,$vars,$xerrors);
         self::save_actions($id, $vars, $errors);
 
-        return true;
+        return count($errors) == 0;
     }
 
     function save_actions($id, $vars, &$errors) {
@@ -545,12 +545,14 @@ class Filter {
                     'type'=>$info,
                     'filter_id'=>$id,
                 ));
-                $I->setConfiguration($errors);
+                $I->setConfiguration($errors, $vars);
                 $I->save();
                 break;
             case 'I': # exiting filter action
-                if ($I = FilterAction::lookup($info))
-                    $I->setConfiguration() && $I->save();
+                if ($I = FilterAction::lookup($info)) {
+                    $I->setConfiguration($errors, $vars);
+                    $I->save();
+                }
                 break;
             case 'D': # deleted filter action
                 if ($I = FilterAction::lookup($info))
diff --git a/include/class.filter_action.php b/include/class.filter_action.php
index b54eabb68db7c6fe819a6b7c848eb7f451cc6e32..14b582a1294cae05a5a8133a563a3c62bdcd6b02 100644
--- a/include/class.filter_action.php
+++ b/include/class.filter_action.php
@@ -32,7 +32,7 @@ class FilterAction extends VerySimpleModel {
         return $this->_config;
     }
 
-    function setConfiguration($source=false, &$errors=array()) {
+    function setConfiguration(&$errors=array(), $source=false) {
         $config = array();
         foreach ($this->getImpl()->getConfigurationForm($source ?: $_POST)
                 ->getFields() as $name=>$field) {
@@ -393,3 +393,50 @@ class FA_SetStatus extends TriggerAction {
     }
 }
 FilterAction::register('FA_SetStatus');
+
+class FA_SendEmail extends TriggerAction {
+    static $type = 'email';
+    static $name = /* trans */ 'Send an Email';
+
+    function apply(&$ticket, array $info) {
+        global $ost;
+
+        $config = $this->getConfiguration();
+        $info = array('subject' => $config['subject'],
+            'message' => $config['message']);
+        $info = $ost->replaceTemplateVariables(
+            $info, array('ticket' => $ticket)
+        );
+        $mailer = new Mailer();
+        $mailer->send($config['recipients'], $info['subject'], $info['message']);
+    }
+
+    function getConfigurationOptions() {
+        return array(
+            'recipients' => new TextboxField(array(
+                'label' => __('Recipients'), 'required' => true,
+                'configuration' => array(
+                    'size' => 80
+                ),
+                'validators' => function($self, $value) {
+                    if (!($q=Validator::is_email($value, true)))
+                        $self->addError('Unable to parse address list. '
+                            .'Use commas to separate addresses.');
+                }
+            )),
+            'subject' => new TextboxField(array(
+                'configuration' => array(
+                    'size' => 80,
+                    'placeholder' => __('Subject')
+                ),
+            )),
+            'message' => new TextareaField(array(
+                'configuration' => array(
+                    'placeholder' => __('Message'),
+                    'html' => true,
+                ),
+            )),
+        );
+    }
+}
+FilterAction::register('FA_SendEmail');
diff --git a/include/class.variable.php b/include/class.variable.php
index 41bcb619e5587ddce96dce8bdb16d1e5aec7994b..ffb850ec8f264dd2e15ada81e37e90b268c0ccec 100644
--- a/include/class.variable.php
+++ b/include/class.variable.php
@@ -79,6 +79,9 @@ class VariableReplacer {
             return $this->getVar($rv, $part);
         }
 
+        if (is_array($obj) && isset($obj[$v]))
+            return $obj[$v];
+
         if (!$var || !method_exists($obj, 'getVar'))
             return "";
 
@@ -112,8 +115,13 @@ class VariableReplacer {
         $parts = explode('.', $var, 2);
         if($parts && ($obj=$this->getObj($parts[0])))
             return $this->getVar($obj, $parts[1]);
-        elseif($parts[0] && @isset($this->variables[$parts[0]])) //root override
+        elseif($parts[0] && @isset($this->variables[$parts[0]])) { //root override
+            if (is_array($this->variables[$parts[0]])
+                    && isset($this->variables[$parts[0]][$parts[1]]))
+                return $this->variables[$parts[0]][$parts[1]];
+
             return $this->variables[$parts[0]];
+        }
 
         //Unknown object or variable - leavig it alone.
         $this->setError(sprintf(__('Unknown object for "%s" tag'), $var));
diff --git a/include/staff/filter.inc.php b/include/staff/filter.inc.php
index 5ef7d36a1482f441ddb470a6a4f45fb6465477d4..169b845e6956ce5db35a5ef2bba56350d5381287 100644
--- a/include/staff/filter.inc.php
+++ b/include/staff/filter.inc.php
@@ -190,7 +190,9 @@ if ($filter) { foreach ($filter->getActions() as $A) {
 ?>
         <tr><td><?php echo $A->getImpl()->getName(); ?>:</td>
             <td><div style="position:relative"><?php
-                $form = $A->getImpl()->getConfigurationForm();
+                $form = $A->getImpl()->getConfigurationForm($_POST ?: false);
+                // XXX: Drop this when the ORM supports proper caching
+                $form->isValid();
                 include STAFFINC_DIR . 'templates/dynamic-form-simple.tmpl.php';
 ?>
                 <input type="hidden" name="actions[]" value="I<?php echo $A->getId(); ?>"/>
@@ -230,7 +232,7 @@ if ($filter) { foreach ($filter->getActions() as $A) {
         $('#dynamic-actions')
           .append($('<tr></tr>')
             .append($('<td></td>')
-              .text(selected.data('title'))
+              .text(selected.data('title') + ':')
             ).append($('<td></td>')
               .append($('<em></em>').text(__('Loading ...')))
               .load('ajax.php/filter/action/' + selected.val() + '/config', function() {