# -*- coding: utf-8 -*-
from django.conf import settings

from tcms.core.utils.mailto import send_email_using_threading


def email_plan_update(plan):
    recipients = get_plan_notification_recipients(plan)
    if len(recipients) == 0:
        return
    subject = u'TestPlan %s has been updated.' % plan.pk
    send_email_using_threading(settings.PLAN_EMAIL_TEMPLATE, subject,
                               recipients, {'plan': plan})


def email_plan_deletion(plan):
    recipients = get_plan_notification_recipients(plan)
    if len(recipients) == 0:
        return
    subject = u'TestPlan %s has been deleted.' % plan.pk
    send_email_using_threading(settings.PLAN_DELELE_EMAIL_TEMPLATE, subject,
                               recipients, {'plan': plan})


def get_plan_notification_recipients(plan):
    recipients = set()
    if plan.owner:
        if plan.email_settings.auto_to_plan_owner:
            recipients.add(plan.owner.email)
    if plan.email_settings.auto_to_plan_author:
        recipients.add(plan.author.email)
    if plan.email_settings.auto_to_case_owner:
        case_authors = plan.case.values_list('author__email', flat=True)
        recipients.update(case_authors)
    if plan.email_settings.auto_to_case_default_tester:
        case_testers = plan.case.values_list('default_tester__email',
                                             flat=True)
        recipients.update(case_testers)
    return filter(lambda e: bool(e), recipients)

tcms/testplans/helpers/email.py
# -*- coding: utf-8 -*-
from django.conf import settings

from tcms.core.utils.mailto import send_email_using_threading


def email_plan_update(plan):
    recipients = get_plan_notification_recipients(plan)
    if len(recipients) == 0:
        return
    subject = u'TestPlan %s has been updated.' % plan.pk
    send_email_using_threading(settings.PLAN_EMAIL_TEMPLATE, subject,
                               recipients, {'plan': plan})


def email_plan_deletion(plan):
    recipients = get_plan_notification_recipients(plan)
    if len(recipients) == 0:
        return
    subject = u'TestPlan %s has been deleted.' % plan.pk
    send_email_using_threading(settings.PLAN_DELELE_EMAIL_TEMPLATE, subject,
                               recipients, {'plan': plan})


def get_plan_notification_recipients(plan):
    recipients = set()
    if plan.owner:
        if plan.email_settings.auto_to_plan_owner:
            recipients.add(plan.owner.email)
    if plan.email_settings.auto_to_plan_author:
        recipients.add(plan.author.email)
    if plan.email_settings.auto_to_case_owner:
        case_authors = plan.case.values_list('author__email', flat=True)
        recipients.update(case_authors)
    if plan.email_settings.auto_to_case_default_tester:
        case_testers = plan.case.values_list('default_tester__email',
                                             flat=True)
        recipients.update(case_testers)
    return [r for r in recipients if r]

tcms/testplans/helpers/email.py
diff --git a/tcms/testplans/helpers/email.py b/tcms/testplans/helpers/email.py
index d127c0eb..2e06c441 100644
--- a/tcms/testplans/helpers/email.py
+++ b/tcms/testplans/helpers/email.py
@@ -36,4 +36,4 @@ def get_plan_notification_recipients(plan):
         case_testers = plan.case.values_list('default_tester__email',
                                              flat=True)
         recipients.update(case_testers)
-    return filter(lambda e: bool(e), recipients)
+    return [r for r in recipients if r]
diff --git a/tcms/testplans/tests/test_models.py b/tcms/testplans/tests/test_models.py
new file mode 100644
index 00000000..3cd5a64b
--- /dev/null
+++ b/tcms/testplans/tests/test_models.py
@@ -0,0 +1,117 @@
+# -*- coding: utf-8 -*-
+
+from django.conf import settings
+from django import test
+from mock import patch
+
+from tcms.testplans.models import _disconnect_signals
+from tcms.testplans.models import _listen
+from tcms.tests.factories import TestCaseFactory
+from tcms.tests.factories import TestPlanEmailSettingsFactory
+from tcms.tests.factories import TestPlanFactory
+from tcms.tests.factories import UserFactory
+
+from tcms.testplans.helpers.email import get_plan_notification_recipients
+
+
+class TestSendEmailOnPlanUpdated(test.TestCase):
+    """Test send email on a plan is updated"""
+
+    @classmethod
+    def setUpTestData(cls):
+        cls.owner = UserFactory(username='owner', email='owner@example.com')
+        cls.plan = TestPlanFactory(owner=cls.owner, author=cls.owner)
+        TestPlanEmailSettingsFactory(
+            auto_to_plan_owner=True,
+            auto_to_plan_author=True,
+            notify_on_plan_update=True,
+            plan=cls.plan)
+
+    def setUp(self):
+        _listen()
+
+    def tearDown(self):
+        _disconnect_signals()
+
+    @patch('tcms.testplans.helpers.email.send_email_using_threading')
+    def test_send_email(self, send_email_using_threading):
+        self.plan.name = 'Update to send email ...'
+        self.plan.save()
+
+        send_email_using_threading.assert_called_once_with(
+            settings.PLAN_EMAIL_TEMPLATE,
+            'TestPlan {} has been updated.'.format(self.plan.pk),
+            ['owner@example.com'],
+            {'plan': self.plan})
+
+
+class TestSendEmailOnPlanDeleted(test.TestCase):
+    """Test send email on a plan is deleted"""
+
+    @classmethod
+    def setUpTestData(cls):
+        cls.owner = UserFactory(username='owner', email='owner@example.com')
+        cls.plan = TestPlanFactory(owner=cls.owner, author=cls.owner)
+        TestPlanEmailSettingsFactory(
+            auto_to_plan_owner=True,
+            auto_to_plan_author=True,
+            notify_on_plan_delete=True,
+            plan=cls.plan)
+
+    def setUp(self):
+        _listen()
+
+    def tearDown(self):
+        _disconnect_signals()
+
+    @patch('tcms.testplans.helpers.email.send_email_using_threading')
+    def test_send_email(self, send_email_using_threading):
+        plan_id = self.plan.pk
+        self.plan.delete()
+
+        send_email_using_threading.assert_called_once_with(
+            settings.PLAN_DELELE_EMAIL_TEMPLATE,
+            'TestPlan {} has been deleted.'.format(plan_id),
+            ['owner@example.com'],
+            {'plan': self.plan})
+
+
+class TestGetPlanNotificationRecipients(test.TestCase):
+    """Test testplans.helpers.email.get_plan_notification_recipients"""
+
+    @classmethod
+    def setUpTestData(cls):
+        cls.owner = UserFactory(username='user1', email='user1@example.com')
+        cls.plan = TestPlanFactory(owner=cls.owner, author=cls.owner)
+        cls.case_1 = TestCaseFactory(
+            author=UserFactory(username='user2', email='user2@example.com'),
+            default_tester=UserFactory(username='user3',
+                                       email='user3@example.com'),
+            plan=[cls.plan])
+        cls.case_2 = TestCaseFactory(
+            author=UserFactory(username='user4', email='user4@example.com'),
+            default_tester=UserFactory(username='user5',
+                                       email='user5@example.com'),
+            plan=[cls.plan])
+        cls.case_3 = TestCaseFactory(
+            author=UserFactory(username='user6', email='user6@example.com'),
+            default_tester=UserFactory(username='user7', email=''),
+            plan=[cls.plan])
+
+        TestPlanEmailSettingsFactory(
+            auto_to_plan_owner=True,
+            auto_to_plan_author=True,
+            auto_to_case_owner=True,
+            auto_to_case_default_tester=True,
+            plan=cls.plan)
+
+    def test_collect_recipients(self):
+        recipients = get_plan_notification_recipients(self.plan)
+        self.assertEqual([
+            'user1@example.com',
+            'user2@example.com',
+            'user3@example.com',
+            'user4@example.com',
+            'user5@example.com',
+            'user6@example.com',
+        ], sorted(recipients))

Fix filter calls
Similar with the calls to `map`, these calls must be fixed as well.
