Repository: cloud-custodian/cloud-custodian

Issue:
Azure - C7n-Mailer - Email Fails to Send using 'resource-owner' and 'Owner_absent_contact '
### Description: 
Trying to send an email without a hard coded email address in the policy results with no email being sent. When specifying 'resource-owner', which should tie to the 'OwnerContact' tag to a specified email, an empty dictionary is returned (which I assume is what custodian mailer defaults to). It also appears that 'owner_absent_contact' also does not get notified. When reverting back to a hard coded email address in the 'to' field, email resumes
### Policy: 
```
policies:
  - name: azure-notify
    resource: azure.resourcegroup
    description: example policy
    actions:
      - type: notify
        template: default
        priority_header: '2'
        subject: Hello from C7N Mailer
        to:
          - resource-owner
        owner_absent_contact:
          - me@me.com
        transport:
          type: asq
          queue: https://myblob.queue.core.windows.net/taskqueue
```
### terminal output:
```
2018-11-01 20:02:32,792 - custodian-mailer - INFO - Sending account:XXXX policy:azure-notify azure.resourcegroup:7 email:default to {}
```


Discussion:
You should be able to specify `tag:OwnerContact` in the `to:` property
#### update:
@aluong @stefangordon @logachev @erwelch 
The function : get_email_to_addrs_to_resources_map"in sendgrid_delivery.py, appears to be sending an empty object to utils_email.py, or the first 'if' block in the is_email function in utils_email.py is causing the ability to send emails via 'tag' not to work:
```
File "/usr/local/lib/python3.6/site-packages/c7n_mailer/utils_email.py", line 8, in is_email
if target.startswith('slack://'):
AttributeError: 'NoneType' object has no attribute 'startswith'
2018-11-02 12:07:13,851 - custodian-mailer - INFO - No messages left on the azure storage queue, exiting c7n_mailer.
```
working policy:
```
policies:

  policies:
  - name: azure-notify
    resource: azure.resourcegroup
    description: example policy
    actions:
      - type: notify
        template: default
        priority_header: '2'
        subject: hello from the mailer
        to:
          - tag:OwnerContact
        transport:
          type: asq
          queue: https://myblob.queue.core.windows.net/taskqueue

```


I commented out lines 8-10 in the is_email functions and sendgrid is able to send emails via tags for Azure. I'll put this in the issue, I know this doesnt help with support of using slack webhooks but how it currently sits its nerfing some email delivery functionality. 

Based on "target.startswith('slack://" I'm guessing slack with API keys is the only currently supported slack output based on the other slack deliver options?

Resolving patch:
diff --git a/tools/c7n_mailer/c7n_mailer/utils_email.py b/tools/c7n_mailer/c7n_mailer/utils_email.py
--- a/tools/c7n_mailer/c7n_mailer/utils_email.py
+++ b/tools/c7n_mailer/c7n_mailer/utils_email.py
@@ -5,6 +5,8 @@
 
 
 def is_email(target):
+    if target is None:
+        return False
     if target.startswith('slack://'):
         logger.debug("Slack payload, not an email.")
         return False


Test patch:
diff --git a/tools/c7n_mailer/tests/common.py b/tools/c7n_mailer/tests/common.py
--- a/tools/c7n_mailer/tests/common.py
+++ b/tools/c7n_mailer/tests/common.py
@@ -244,6 +244,57 @@
    ]
 }'''
 
+ASQ_MESSAGE_TAG = '''{
+   "account":"subscription",
+   "account_id":"ee98974b-5d2a-4d98-a78a-382f3715d07e",
+   "region":"all",
+   "action":{
+      "to":[
+         "tag:owner"
+      ],
+      "template":"default",
+      "priority_header":"2",
+      "type":"notify",
+      "transport":{
+         "queue":"https://test.queue.core.windows.net/testcc",
+         "type":"asq"
+      },
+      "subject":"testing notify action"
+   },
+   "policy":{
+      "resource":"azure.keyvault",
+      "name":"test-notify-for-keyvault",
+      "actions":[
+         {
+            "to":[
+               "tag:owner"
+            ],
+            "template":"default",
+            "priority_header":"2",
+            "type":"notify",
+            "transport":{
+               "queue":"https://test.queue.core.windows.net/testcc",
+               "type":"asq"
+            },
+            "subject":"testing notify action"
+         }
+      ]
+   },
+   "event":null,
+   "resources":[
+      {
+         "name":"cckeyvault1",
+         "tags":{
+            "owner":"user@domain.com"
+         },
+         "resourceGroup":"test_keyvault",
+         "location":"southcentralus",
+         "type":"Microsoft.KeyVault/vaults",
+         "id":"/subscriptions/ee98974b-5d2a-4d98-a78a-382f3715d07e/resourceGroups/test_keyvault/providers/Microsoft.KeyVault/vaults/cckeyvault1"
+      }
+   ]
+}'''
+
 
 # Monkey-patch ldap3 to work around a bytes/text handling bug.
 
diff --git a/tools/c7n_mailer/tests/test_azure.py b/tools/c7n_mailer/tests/test_azure.py
--- a/tools/c7n_mailer/tests/test_azure.py
+++ b/tools/c7n_mailer/tests/test_azure.py
@@ -19,7 +19,8 @@
 
 from c7n_azure.storage_utils import StorageUtilities
 from c7n_mailer.azure.azure_queue_processor import MailerAzureQueueProcessor
-from common import MAILER_CONFIG_AZURE, ASQ_MESSAGE, logger
+from c7n_mailer.azure.sendgrid_delivery import SendGridDelivery
+from common import MAILER_CONFIG_AZURE, ASQ_MESSAGE, ASQ_MESSAGE_TAG, logger
 from mock import MagicMock, patch
 
 
@@ -31,6 +32,8 @@ def setUp(self):
             zlib.compress(ASQ_MESSAGE.encode('utf8')))
         self.loaded_message = json.loads(ASQ_MESSAGE)
 
+        self.tag_message = json.loads(ASQ_MESSAGE_TAG)
+
     @patch('c7n_mailer.azure.sendgrid_delivery.SendGridDelivery.sendgrid_handler')
     @patch('c7n_mailer.azure.sendgrid_delivery.SendGridDelivery.get_to_addrs_sendgrid_messages_map')
     def test_process_azure_queue_message_success(self, mock_get_addr, mock_handler):
@@ -75,3 +78,18 @@ def test_run(self, mock_get_messages, mock_delete, mock_client, mock_process):
         self.assertEqual(2, mock_get_messages.call_count)
         self.assertEqual(1, mock_process.call_count)
         mock_delete.assert_called()
+
+    def test_get_email_to_addrs_to_resources_map_tag(self):
+        delivery = SendGridDelivery(MAILER_CONFIG_AZURE, logger)
+        result_map = delivery.get_email_to_addrs_to_resources_map(self.tag_message)
+        self.assertEqual(list(result_map.keys())[0][0], 'user@domain.com')
+
+    def test_get_email_to_addrs_to_resources_map_null_tag(self):
+        delivery = SendGridDelivery(MAILER_CONFIG_AZURE, logger)
+
+        # null out tags
+        message = self.tag_message
+        message['resources'][0]['tags'] = {}
+
+        result_map = delivery.get_email_to_addrs_to_resources_map(message)
+        self.assertEqual(len(result_map.keys()), 0)