diff --git a/includes/webform.submissions.inc b/includes/webform.submissions.inc
index 94d61d3..66b9057 100644
--- a/includes/webform.submissions.inc
+++ b/includes/webform.submissions.inc
@@ -658,19 +658,16 @@ function webform_submission_render($node, $submission, $email, $format, $exclude
     foreach ($excluded_components as $cid) {
       unset($components[$cid]);
     }
-    if (!empty($email['exclude_empty'])) {
-      foreach ($submission->data as $cid => $data) {
-        // Caution. Grids store their data in an array index by question key.
-        if (implode($data) == '') {
-          unset($components[$cid]);
-        }
-      }
-    }
   }
 
   module_load_include('inc', 'webform', 'includes/webform.components');
   _webform_components_tree_build($components, $component_tree, 0, $page_count);
 
+  if (!empty($email['exclude_empty'])) {
+    $excluded_components = module_invoke_all('webform_submission_exclude_empty_excluded_components');
+    _webform_submission_remove_empty_components($submission->data, $components, $component_tree, $excluded_components);
+  }
+
   // Make sure at least one field is available.
   if (isset($component_tree['children'])) {
     // Recursively add components to the form.
@@ -688,6 +685,62 @@ function webform_submission_render($node, $submission, $email, $format, $exclude
 }
 
 /**
+ * Remove all components without values and all fieldsets without children.
+ *
+ * @param $data
+ *   Submission data from webform_submission_render().
+ * @param $components
+ *   Components from webform_submission_render().
+ * @param $tree
+ *   Component tree or child tree from webform_submission_render() or recursion.
+ * @param array $excluded_types
+ *   Component types that should never be removed.
+ *
+ * @return bool
+ *   TRUE: tree doesn't have children.
+ *   FALSE: tree has children.
+ */
+function _webform_submission_remove_empty_components($data, &$components, &$tree, array $excluded_types = array()) {
+  foreach ($tree['children'] as $key => $child) {
+    // Ignore excluded types.
+    if (!in_array($child['type'], $excluded_types)) {
+      // Check if this child is empty.
+      if (!isset($data[$child['cid']]) || (is_array($data[$key]) && _webform_submission_recursive_is_empty_array($data[$key]))) {
+        // If not fieldset or a component that supports grouping remove, if fieldset or other group do recursion and remove if empty.
+        if (
+          !webform_component_feature($child['type'], 'group') ||
+          _webform_submission_remove_empty_components($data, $components, $tree['children'][$key], $excluded_types)
+        ) {
+          unset($tree['children'][$key]);
+          unset($components[$key]);
+        }
+      }
+    }
+  }
+
+  // Return if leftover children so the recursion knows if the fieldset can be removed or not.
+  return count($tree['children']) == 0;
+}
+
+/**
+ * Checks if an array is empty, regardless of how many levels there are in the array.
+ */
+function _webform_submission_recursive_is_empty_array(array $array) {
+  foreach ($array as $key => $value) {
+    if (!is_array($value)) {
+      if (!empty($value)) {
+        return FALSE;
+      }
+    }
+    elseif (!_webform_submission_recursive_is_empty_array($value)) {
+      return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
+/**
  * Return all the submissions for a particular node.
  *
  * @param $filters
diff --git a/webform.api.php b/webform.api.php
index 6180f57..94842bb 100644
--- a/webform.api.php
+++ b/webform.api.php
@@ -277,6 +277,19 @@ function hook_webform_submission_render_alter(&$renderable) {
 }
 
 /**
+ * Define component types that should never be removed when
+ * "Exclude empty components" is enabled for webform emails.
+ *
+ * @return array
+ *   Component types that should be excluded.
+ */
+function hook_webform_submission_exclude_empty_excluded_components() {
+  return array(
+    'pagebreak',
+  );
+}
+
+/**
  * Modify a loaded Webform component.
  *
  * IMPORTANT: This hook does not actually exist because components are loaded
