Repository: ansible/ansible

Issue:
Mail callback plugin returning 'TaskResult' object has no attribute '__getitem__'
<!--- Verify first that your issue/request is not already reported in GitHub -->
##### ISSUE TYPE

<!--- Pick one below and delete the rest: -->
- Bug Report
##### ANSIBLE VERSION

```
ansible-playbook 2.0.0.2
```
##### CONFIGURATION

<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->
##### OS / ENVIRONMENT

N/A
##### SUMMARY

When calling the mail callback using shell/command modules failed emails are never sent. Callback returns 'TaskResult' object has no attribute '**getitem**'.  I have tested with the hipchat and template modules and they work. 
##### STEPS TO REPRODUCE

ansible-playbook -i inventory site.yml

```
- hosts: all
  become: yes
  gather_facts: False

  tasks:
    - name: test
      shell: ls /zzz

```

<!--- You can also paste gist.github.com links for larger files -->
##### EXPECTED RESULTS

Email to be sent detailing what failed on the host.
##### ACTUAL RESULTS

<!--- What actually happened? If possible run with high verbosity (-vvvv) -->

```
Loaded callback mail of type notification, v2.0
Loaded callback default of type stdout, v2.0
Loaded callback timer of type aggregate, v2.0
1 plays in site.yml

PLAY ***************************************************************************

TASK [test] ********************************************************************
task path: /ansible/test/site.yml:7
<host.example.com> ESTABLISH SSH CONNECTION FOR USER: user
<host.example.com> SSH: ansible.cfg set ssh_args: (-o)(ControlMaster=auto)(-o)(ControlPersist=60s)
<host.example.com> SSH: ANSIBLE_HOST_KEY_CHECKING/host_key_checking disabled: (-o)(StrictHostKeyChecking=no)
<host.example.com> SSH: ANSIBLE_REMOTE_PORT/remote_port/ansible_port set: (-o)(Port=22)
<host.example.com> SSH: ANSIBLE_REMOTE_USER/remote_user/ansible_user/user/-u set: (-o)(User=user)
<host.example.com> SSH: ANSIBLE_TIMEOUT/timeout set: (-o)(ConnectTimeout=10)
<host.example.com> SSH: PlayContext set ssh_common_args: ()
<host.example.com> SSH: PlayContext set ssh_extra_args: ()
<host.example.com> SSH: found only ControlPersist; added ControlPath: (-o)(ControlPath=/tmp/ansible-ssh-%h-%p-%r)
<host.example.com> SSH: EXEC sshpass -d14 ssh -C -vvv -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o Port=22 -o User=user -o ConnectTimeout=10 -o ControlPath=/tmp/ansible-ssh-%h-%p-%r -tt host.example.com '( umask 22 && mkdir -p "$( echo /tmp/$USER/.ansible/tmp/ansible-tmp-1460049501.07-176314225541704 )" && echo "$( echo /tmp/$USER/.ansible/tmp/ansible-tmp-1460049501.07-176314225541704 )" )'
<host.example.com> PUT /tmp/tmp2U4eCN TO /tmp/user/.ansible/tmp/ansible-tmp-1460049501.07-176314225541704/command
<host.example.com> SSH: ansible.cfg set ssh_args: (-o)(ControlMaster=auto)(-o)(ControlPersist=60s)
<host.example.com> SSH: ANSIBLE_HOST_KEY_CHECKING/host_key_checking disabled: (-o)(StrictHostKeyChecking=no)
<host.example.com> SSH: ANSIBLE_REMOTE_PORT/remote_port/ansible_port set: (-o)(Port=22)
<host.example.com> SSH: ANSIBLE_REMOTE_USER/remote_user/ansible_user/user/-u set: (-o)(User=user)
<host.example.com> SSH: ANSIBLE_TIMEOUT/timeout set: (-o)(ConnectTimeout=10)
<host.example.com> SSH: PlayContext set ssh_common_args: ()
<host.example.com> SSH: PlayContext set sftp_extra_args: ()
<host.example.com> SSH: found only ControlPersist; added ControlPath: (-o)(ControlPath=/tmp/ansible-ssh-%h-%p-%r)
<host.example.com> SSH: EXEC sshpass -d14 sftp -b - -C -vvv -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o Port=22 -o User=user -o ConnectTimeout=10 -o ControlPath=/tmp/ansible-ssh-%h-%p-%r '[host.example.com]'
<host.example.com> ESTABLISH SSH CONNECTION FOR USER: user
<host.example.com> SSH: ansible.cfg set ssh_args: (-o)(ControlMaster=auto)(-o)(ControlPersist=60s)
<host.example.com> SSH: ANSIBLE_HOST_KEY_CHECKING/host_key_checking disabled: (-o)(StrictHostKeyChecking=no)
<host.example.com> SSH: ANSIBLE_REMOTE_PORT/remote_port/ansible_port set: (-o)(Port=22)
<host.example.com> SSH: ANSIBLE_REMOTE_USER/remote_user/ansible_user/user/-u set: (-o)(User=user)
<host.example.com> SSH: ANSIBLE_TIMEOUT/timeout set: (-o)(ConnectTimeout=10)
<host.example.com> SSH: PlayContext set ssh_common_args: ()
<host.example.com> SSH: PlayContext set ssh_extra_args: ()
<host.example.com> SSH: found only ControlPersist; added ControlPath: (-o)(ControlPath=/tmp/ansible-ssh-%h-%p-%r)
<host.example.com> SSH: EXEC sshpass -d14 ssh -C -vvv -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o Port=22 -o User=user -o ConnectTimeout=10 -o ControlPath=/tmp/ansible-ssh-%h-%p-%r -tt host.example.com '/bin/sh -c '"'"'/usr/local/bin/sudo -H -S  -p "[sudo via ansible, key=axcpuewcpxursrcrenpsogambsuupbzp] password: " -u root /bin/sh -c '"'"'"'"'"'"'"'"'echo BECOME-SUCCESS-axcpuewcpxursrcrenpsogambsuupbzp; LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 /usr/bin/python /tmp/user/.ansible/tmp/ansible-tmp-1460049501.07-176314225541704/command; rm -rf "/tmp/user/.ansible/tmp/ansible-tmp-1460049501.07-176314225541704/" > /dev/null 2>&1'"'"'"'"'"'"'"'"''"'"''
 [WARNING]: Error when using <bound method CallbackModule.v2_runner_on_failed of </ansible/test/callback_plugins/mail.CallbackModule object at 0x7efdbb332e50>>:
'TaskResult' object has no attribute '__getitem__'

fatal: [host.example.com]: FAILED! => {"changed": true, "cmd": "ls /zzz", "delta": "0:00:00.011880", "end": "2016-04-07 17:18:23.693285", "failed": true, "invocation": {"module_args": {"_raw_params": "ls /zzz", "_uses_shell": true, "chdir": null, "creates": null, "executable": null, "removes": null, "warn": true}, "module_name": "command"}, "rc": 2, "start": "2016-04-07 17:18:23.681405", "stderr": "ls: cannot access /zzz: No such file or directory", "stdout": "", "stdout_lines": [], "warnings": []}

PLAY RECAP *********************************************************************
host.example.com     : ok=0    changed=0    unreachable=0    failed=1
```



Discussion:
There seems to be a typo in mail.py. I changed 1 line no it works for me.

```
 if 'stderr' in res._result.keys() and res._result['stderr']:
     # subject = res['stderr'].strip('\r\n').split('\n')[-1]
     subject = res._result['stderr'].strip('\r\n').split('\n')[-1]
```

Additionally I removed to cc/bcc code as tries to send mails to None

```
# if b_cc:
#     b_addresses += b_cc.split(b',')
# if b_bcc:
#     b_addresses += b_bcc.split(b',')
```

Same here in ansible 2.1 so :+1:, needs fixing

Confirmed that the fix proposed by @mundus08 works.

@mundus08 subit a pull request and lets get this fixed!


Resolving patch:
diff --git a/lib/ansible/plugins/callback/mail.py b/lib/ansible/plugins/callback/mail.py
--- a/lib/ansible/plugins/callback/mail.py
+++ b/lib/ansible/plugins/callback/mail.py
@@ -94,7 +94,7 @@ def v2_runner_on_failed(self, res, ignore_errors=False):
             subject = res._result['stdout'].strip('\r\n').split('\n')[-1]
             body += 'with the following output in standard output:\n\n' + res._result['stdout'] + '\n\n'
         if 'stderr' in res._result.keys() and res._result['stderr']:
-            subject = res['stderr'].strip('\r\n').split('\n')[-1]
+            subject = res._result['stderr'].strip('\r\n').split('\n')[-1]
             body += 'with the following output in standard error:\n\n' + res._result['stderr'] + '\n\n'
         if 'msg' in res._result.keys() and res._result['msg']:
             subject = res._result['msg'].strip('\r\n').split('\n')[0]


Test patch: