We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Ansible Reports Twilio Failure Yet SMS Sent Successfullly
<!--- Verify first that your issue/request is not already reported in GitHub -->
##### ISSUE TYPE

<!--- Pick one below and delete the rest: -->
- Bug Report
##### COMPONENT NAME

<!--- Name of the plugin/module/task -->

Twilio
##### ANSIBLE VERSION

<!--- Paste verbatim output from “ansible --version” between quotes below -->

```
ansible 2.1.1.0
  config file = /home/douglas/repos/ansible/ansible.cfg
  configured module search path = Default w/o overrides
```
##### CONFIGURATION

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

```
Pipelining and threads but nothing else

```
##### OS / ENVIRONMENT

<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
-->

```
Linux Mint

```
##### SUMMARY

<!--- Explain the problem briefly -->

```

TASK [accounts : send sms challenge] *******************************************
fatal: [pascal -> localhost]: FAILED! => {"changed": false, "failed": true, "msg": "unable to send message to +15163205079"}
...ignoring

Yet Twilio console shows SMS delivered while recipient confirms SMS 

```
##### STEPS TO REPRODUCE

<!---
For bugs, show exactly how to reproduce the problem.
For new features, show how the feature would be used.
-->

<!--- Paste example playbooks or commands between quotes below -->

```
ansible-playbook accounts.yml "-e hosts=server -e csms=[] -e number=+blah -e user=blah" -t csms --sudo -K --ask-vault-pass

cat accounts.yml 

---
- hosts: "{{ hosts }}"
  roles: 
    - accounts
  gather_facts: True


cat roles/accounts/tasks/main.yml 

- include: create_user.yml
  when: create is defined

- include: remove_user.yml
  when: remove is defined

- include: xfs.yml
  when: ansible_hostname == "blah" or "blah"

- include: lab_email.yml
  when: lab is defined

- include: challenge.yml
  when: csms is defined

cat roles/accounts/tasks/challenge.yml 

- name: send sms challenge
  tags: csms 
  twilio:
   msg: "{{ challenge }}"
   account_sid: "SID"
   auth_token: "TOKEN"
   from_number: "+BLAH"
   to_number: "{{ number }}"
  delegate_to: localhost    
  ignore_errors: True

```

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

<!--- What did you expect to happen when running the steps above? -->

SMS works without reported error
##### ACTUAL RESULTS

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

SMS works but module reports error 

<!--- Paste verbatim command output between quotes below -->

```

 ansible-playbook accounts.yml "-e hosts=host -e csms=[] -e number=+blah -e user=blah" -t csms --sudo -K --ask-vault-pass -vvv
Using /home/user/repos/ansible/ansible.cfg as config file
SUDO password: 
Vault password: 

PLAYBOOK: accounts.yml *********************************************************
1 plays in accounts.yml

PLAY [pascal] ******************************************************************

TASK [setup] *******************************************************************
<pascal> ESTABLISH SSH CONNECTION FOR USER: None
<pascal> SSH: EXEC ssh -C -q -o ControlMaster=auto -o ControlPersist=60s -o Port=22 -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=20 -o ControlPath=/home/user/.ansible/cp/ansible-ssh-%h-%p-%r host '/bin/sh -c '"'"'sudo -H -S  -p "[sudo via ansible, key=dovdppgsmmkpysizwmmmanqpnsnbhkbn] password: " -u root /bin/sh -c '"'"'"'"'"'"'"'"'echo BECOME-SUCCESS-dovdppgsmmkpysizwmmmanqpnsnbhkbn; LANG=C LC_ALL=C LC_MESSAGES=C /usr/bin/python'"'"'"'"'"'"'"'"' && sleep 0'"'"''
ok: [pascal]

TASK [accounts : send sms challenge] *******************************************
task path: /home/user/repos/ansible/playbooks/roles/accounts/tasks/challenge.yml:11
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: user
<localhost> EXEC /bin/sh -c 'sudo -H -S  -p "[sudo via ansible, key=pgyfxtpxffqiposwtecseosepacqessa] password: " -u root /bin/sh -c '"'"'echo BECOME-SUCCESS-pgyfxtpxffqiposwtecseosepacqessa; LANG=C LC_ALL=C LC_MESSAGES=C /usr/bin/python'"'"' && sleep 0'
fatal: [user -> localhost]: FAILED! => {"changed": false, "failed": true, "invocation": {"module_args": {"account_sid": "blah", "auth_token": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", "from_number": "+blah", "media_url": null, "msg": "challenge", "to_number": "+blahblah", "url_password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", "url_username": "blah"}, "module_name": "twilio"}, "msg": "unable to send message to +blah"}
...ignoring

PLAY RECAP *********************************************************************
host                     : ok=2    changed=0    unreachable=0    failed=0   

```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `notification/twilio.py`
Content:
```
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 
4 # (c) 2015, Matt Makai <matthew.makai@gmail.com>
5 #
6 # This file is part of Ansible
7 #
8 # Ansible is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # Ansible is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
20 
21 DOCUMENTATION = '''
22 ---
23 version_added: "1.6"
24 module: twilio
25 short_description: Sends a text message to a mobile phone through Twilio.
26 description:
27    - Sends a text message to a phone number through the Twilio messaging API.
28 notes:
29    - This module is non-idempotent because it sends an email through the
30      external API. It is idempotent only in the case that the module fails.
31    - Like the other notification modules, this one requires an external
32      dependency to work. In this case, you'll need a Twilio account with
33      a purchased or verified phone number to send the text message.
34 options:
35   account_sid:
36     description:
37       user's Twilio account token found on the account page
38     required: true
39   auth_token:
40     description: user's Twilio authentication token
41     required: true
42   msg:
43     description:
44       the body of the text message
45     required: true
46   to_number:
47     description:
48       one or more phone numbers to send the text message to,
49       format +15551112222
50     required: true
51   from_number:
52     description:
53       the Twilio number to send the text message from, format +15551112222
54     required: true
55   media_url:
56     description:
57       a URL with a picture, video or sound clip to send with an MMS
58       (multimedia message) instead of a plain SMS
59     required: false
60 
61 author: "Matt Makai (@makaimc)"
62 '''
63 
64 EXAMPLES = '''
65 # send an SMS about the build status to (555) 303 5681
66 # note: replace account_sid and auth_token values with your credentials
67 # and you have to have the 'from_number' on your Twilio account
68 - twilio:
69     msg: "All servers with webserver role are now configured."
70     account_sid: "ACXXXXXXXXXXXXXXXXX"
71     auth_token: "ACXXXXXXXXXXXXXXXXX"
72     from_number: "+15552014545"
73     to_number: "+15553035681"
74   delegate_to: localhost
75 
76 # send an SMS to multiple phone numbers about the deployment
77 # note: replace account_sid and auth_token values with your credentials
78 # and you have to have the 'from_number' on your Twilio account
79 - twilio:
80     msg: "This server's configuration is now complete."
81     account_sid: "ACXXXXXXXXXXXXXXXXX"
82     auth_token: "ACXXXXXXXXXXXXXXXXX"
83     from_number: "+15553258899"
84     to_number:
85       - "+15551113232"
86       - "+12025551235"
87       - "+19735559010"
88   delegate_to: localhost
89 
90 # send an MMS to a single recipient with an update on the deployment
91 # and an image of the results
92 # note: replace account_sid and auth_token values with your credentials
93 # and you have to have the 'from_number' on your Twilio account
94 - twilio:
95     msg: "Deployment complete!"
96     account_sid: "ACXXXXXXXXXXXXXXXXX"
97     auth_token: "ACXXXXXXXXXXXXXXXXX"
98     from_number: "+15552014545"
99     to_number: "+15553035681"
100     media_url: "https://demo.twilio.com/logo.png"
101   delegate_to: localhost
102 '''
103 
104 # =======================================
105 # twilio module support methods
106 #
107 import urllib
108 
109 
110 def post_twilio_api(module, account_sid, auth_token, msg, from_number,
111                     to_number, media_url=None):
112     URI = "https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json" \
113         % (account_sid,)
114     AGENT = "Ansible"
115 
116     data = {'From':from_number, 'To':to_number, 'Body':msg}
117     if media_url:
118         data['MediaUrl'] = media_url
119     encoded_data = urllib.urlencode(data)
120 
121     headers = {'User-Agent': AGENT,
122             'Content-type': 'application/x-www-form-urlencoded',
123             'Accept': 'application/json',
124             }
125 
126     # Hack module params to have the Basic auth params that fetch_url expects
127     module.params['url_username'] = account_sid.replace('\n', '')
128     module.params['url_password'] = auth_token.replace('\n', '')
129 
130     return fetch_url(module, URI, data=encoded_data, headers=headers)
131 
132 
133 # =======================================
134 # Main
135 #
136 
137 def main():
138 
139     module = AnsibleModule(
140         argument_spec=dict(
141             account_sid=dict(required=True),
142             auth_token=dict(required=True, no_log=True),
143             msg=dict(required=True),
144             from_number=dict(required=True),
145             to_number=dict(required=True),
146             media_url=dict(default=None, required=False),
147         ),
148         supports_check_mode=True
149     )
150 
151     account_sid = module.params['account_sid']
152     auth_token = module.params['auth_token']
153     msg = module.params['msg']
154     from_number = module.params['from_number']
155     to_number = module.params['to_number']
156     media_url = module.params['media_url']
157 
158     if not isinstance(to_number, list):
159         to_number = [to_number]
160 
161     for number in to_number:
162         r, info = post_twilio_api(module, account_sid, auth_token, msg,
163                 from_number, number, media_url)
164         if info['status'] != 200:
165             module.fail_json(msg="unable to send message to %s" % number)
166 
167     module.exit_json(msg=msg, changed=False)
168 
169 # import module snippets
170 from ansible.module_utils.basic import *
171 from ansible.module_utils.urls import *
172 if __name__ == '__main__':
173     main()
174
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/notification/twilio.py b/notification/twilio.py
--- a/notification/twilio.py
+++ b/notification/twilio.py
@@ -161,8 +161,12 @@
     for number in to_number:
         r, info = post_twilio_api(module, account_sid, auth_token, msg,
                 from_number, number, media_url)
-        if info['status'] != 200:
-            module.fail_json(msg="unable to send message to %s" % number)
+        if info['status'] not in [200, 201]:
+            body_message = "unknown error"
+            if 'body' in info:
+                body = json.loads(info['body'])
+                body_message = body['message']
+            module.fail_json(msg="unable to send message to %s: %s" % (number, body_message))
 
     module.exit_json(msg=msg, changed=False)

{"golden_diff": "diff --git a/notification/twilio.py b/notification/twilio.py\n--- a/notification/twilio.py\n+++ b/notification/twilio.py\n@@ -161,8 +161,12 @@\n     for number in to_number:\n         r, info = post_twilio_api(module, account_sid, auth_token, msg,\n                 from_number, number, media_url)\n-        if info['status'] != 200:\n-            module.fail_json(msg=\"unable to send message to %s\" % number)\n+        if info['status'] not in [200, 201]:\n+            body_message = \"unknown error\"\n+            if 'body' in info:\n+                body = json.loads(info['body'])\n+                body_message = body['message']\n+            module.fail_json(msg=\"unable to send message to %s: %s\" % (number, body_message))\n \n     module.exit_json(msg=msg, changed=False)\n", "issue": "Ansible Reports Twilio Failure Yet SMS Sent Successfullly\n<!--- Verify first that your issue/request is not already reported in GitHub -->\n##### ISSUE TYPE\n\n<!--- Pick one below and delete the rest: -->\n- Bug Report\n##### COMPONENT NAME\n\n<!--- Name of the plugin/module/task -->\n\nTwilio\n##### ANSIBLE VERSION\n\n<!--- Paste verbatim output from \u201cansible --version\u201d between quotes below -->\n\n```\nansible 2.1.1.0\n  config file = /home/douglas/repos/ansible/ansible.cfg\n  configured module search path = Default w/o overrides\n```\n##### CONFIGURATION\n\n<!---\nMention any settings you have changed/added/removed in ansible.cfg\n(or using the ANSIBLE_* environment variables).\n-->\n\n```\nPipelining and threads but nothing else\n\n```\n##### OS / ENVIRONMENT\n\n<!---\nMention the OS you are running Ansible from, and the OS you are\nmanaging, or say \u201cN/A\u201d for anything that is not platform-specific.\n-->\n\n```\nLinux Mint\n\n```\n##### SUMMARY\n\n<!--- Explain the problem briefly -->\n\n```\n\nTASK [accounts : send sms challenge] *******************************************\nfatal: [pascal -> localhost]: FAILED! => {\"changed\": false, \"failed\": true, \"msg\": \"unable to send message to +15163205079\"}\n...ignoring\n\nYet Twilio console shows SMS delivered while recipient confirms SMS \n\n```\n##### STEPS TO REPRODUCE\n\n<!---\nFor bugs, show exactly how to reproduce the problem.\nFor new features, show how the feature would be used.\n-->\n\n<!--- Paste example playbooks or commands between quotes below -->\n\n```\nansible-playbook accounts.yml \"-e hosts=server -e csms=[] -e number=+blah -e user=blah\" -t csms --sudo -K --ask-vault-pass\n\ncat accounts.yml \n\n---\n- hosts: \"{{ hosts }}\"\n  roles: \n    - accounts\n  gather_facts: True\n\n\ncat roles/accounts/tasks/main.yml \n\n- include: create_user.yml\n  when: create is defined\n\n- include: remove_user.yml\n  when: remove is defined\n\n- include: xfs.yml\n  when: ansible_hostname == \"blah\" or \"blah\"\n\n- include: lab_email.yml\n  when: lab is defined\n\n- include: challenge.yml\n  when: csms is defined\n\ncat roles/accounts/tasks/challenge.yml \n\n- name: send sms challenge\n  tags: csms \n  twilio:\n   msg: \"{{ challenge }}\"\n   account_sid: \"SID\"\n   auth_token: \"TOKEN\"\n   from_number: \"+BLAH\"\n   to_number: \"{{ number }}\"\n  delegate_to: localhost    \n  ignore_errors: True\n\n```\n\n<!--- You can also paste gist.github.com links for larger files -->\n##### EXPECTED RESULTS\n\n<!--- What did you expect to happen when running the steps above? -->\n\nSMS works without reported error\n##### ACTUAL RESULTS\n\n<!--- What actually happened? If possible run with high verbosity (-vvvv) -->\n\nSMS works but module reports error \n\n<!--- Paste verbatim command output between quotes below -->\n\n```\n\n ansible-playbook accounts.yml \"-e hosts=host -e csms=[] -e number=+blah -e user=blah\" -t csms --sudo -K --ask-vault-pass -vvv\nUsing /home/user/repos/ansible/ansible.cfg as config file\nSUDO password: \nVault password: \n\nPLAYBOOK: accounts.yml *********************************************************\n1 plays in accounts.yml\n\nPLAY [pascal] ******************************************************************\n\nTASK [setup] *******************************************************************\n<pascal> ESTABLISH SSH CONNECTION FOR USER: None\n<pascal> SSH: EXEC ssh -C -q -o ControlMaster=auto -o ControlPersist=60s -o Port=22 -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=20 -o ControlPath=/home/user/.ansible/cp/ansible-ssh-%h-%p-%r host '/bin/sh -c '\"'\"'sudo -H -S  -p \"[sudo via ansible, key=dovdppgsmmkpysizwmmmanqpnsnbhkbn] password: \" -u root /bin/sh -c '\"'\"'\"'\"'\"'\"'\"'\"'echo BECOME-SUCCESS-dovdppgsmmkpysizwmmmanqpnsnbhkbn; LANG=C LC_ALL=C LC_MESSAGES=C /usr/bin/python'\"'\"'\"'\"'\"'\"'\"'\"' && sleep 0'\"'\"''\nok: [pascal]\n\nTASK [accounts : send sms challenge] *******************************************\ntask path: /home/user/repos/ansible/playbooks/roles/accounts/tasks/challenge.yml:11\n<localhost> ESTABLISH LOCAL CONNECTION FOR USER: user\n<localhost> EXEC /bin/sh -c 'sudo -H -S  -p \"[sudo via ansible, key=pgyfxtpxffqiposwtecseosepacqessa] password: \" -u root /bin/sh -c '\"'\"'echo BECOME-SUCCESS-pgyfxtpxffqiposwtecseosepacqessa; LANG=C LC_ALL=C LC_MESSAGES=C /usr/bin/python'\"'\"' && sleep 0'\nfatal: [user -> localhost]: FAILED! => {\"changed\": false, \"failed\": true, \"invocation\": {\"module_args\": {\"account_sid\": \"blah\", \"auth_token\": \"VALUE_SPECIFIED_IN_NO_LOG_PARAMETER\", \"from_number\": \"+blah\", \"media_url\": null, \"msg\": \"challenge\", \"to_number\": \"+blahblah\", \"url_password\": \"VALUE_SPECIFIED_IN_NO_LOG_PARAMETER\", \"url_username\": \"blah\"}, \"module_name\": \"twilio\"}, \"msg\": \"unable to send message to +blah\"}\n...ignoring\n\nPLAY RECAP *********************************************************************\nhost                     : ok=2    changed=0    unreachable=0    failed=0   \n\n```\n\n", "before_files": [{"content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n# (c) 2015, Matt Makai <matthew.makai@gmail.com>\n#\n# This file is part of Ansible\n#\n# Ansible is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# Ansible is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.\n\nDOCUMENTATION = '''\n---\nversion_added: \"1.6\"\nmodule: twilio\nshort_description: Sends a text message to a mobile phone through Twilio.\ndescription:\n   - Sends a text message to a phone number through the Twilio messaging API.\nnotes:\n   - This module is non-idempotent because it sends an email through the\n     external API. It is idempotent only in the case that the module fails.\n   - Like the other notification modules, this one requires an external\n     dependency to work. In this case, you'll need a Twilio account with\n     a purchased or verified phone number to send the text message.\noptions:\n  account_sid:\n    description:\n      user's Twilio account token found on the account page\n    required: true\n  auth_token:\n    description: user's Twilio authentication token\n    required: true\n  msg:\n    description:\n      the body of the text message\n    required: true\n  to_number:\n    description:\n      one or more phone numbers to send the text message to,\n      format +15551112222\n    required: true\n  from_number:\n    description:\n      the Twilio number to send the text message from, format +15551112222\n    required: true\n  media_url:\n    description:\n      a URL with a picture, video or sound clip to send with an MMS\n      (multimedia message) instead of a plain SMS\n    required: false\n\nauthor: \"Matt Makai (@makaimc)\"\n'''\n\nEXAMPLES = '''\n# send an SMS about the build status to (555) 303 5681\n# note: replace account_sid and auth_token values with your credentials\n# and you have to have the 'from_number' on your Twilio account\n- twilio:\n    msg: \"All servers with webserver role are now configured.\"\n    account_sid: \"ACXXXXXXXXXXXXXXXXX\"\n    auth_token: \"ACXXXXXXXXXXXXXXXXX\"\n    from_number: \"+15552014545\"\n    to_number: \"+15553035681\"\n  delegate_to: localhost\n\n# send an SMS to multiple phone numbers about the deployment\n# note: replace account_sid and auth_token values with your credentials\n# and you have to have the 'from_number' on your Twilio account\n- twilio:\n    msg: \"This server's configuration is now complete.\"\n    account_sid: \"ACXXXXXXXXXXXXXXXXX\"\n    auth_token: \"ACXXXXXXXXXXXXXXXXX\"\n    from_number: \"+15553258899\"\n    to_number:\n      - \"+15551113232\"\n      - \"+12025551235\"\n      - \"+19735559010\"\n  delegate_to: localhost\n\n# send an MMS to a single recipient with an update on the deployment\n# and an image of the results\n# note: replace account_sid and auth_token values with your credentials\n# and you have to have the 'from_number' on your Twilio account\n- twilio:\n    msg: \"Deployment complete!\"\n    account_sid: \"ACXXXXXXXXXXXXXXXXX\"\n    auth_token: \"ACXXXXXXXXXXXXXXXXX\"\n    from_number: \"+15552014545\"\n    to_number: \"+15553035681\"\n    media_url: \"https://demo.twilio.com/logo.png\"\n  delegate_to: localhost\n'''\n\n# =======================================\n# twilio module support methods\n#\nimport urllib\n\n\ndef post_twilio_api(module, account_sid, auth_token, msg, from_number,\n                    to_number, media_url=None):\n    URI = \"https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json\" \\\n        % (account_sid,)\n    AGENT = \"Ansible\"\n\n    data = {'From':from_number, 'To':to_number, 'Body':msg}\n    if media_url:\n        data['MediaUrl'] = media_url\n    encoded_data = urllib.urlencode(data)\n\n    headers = {'User-Agent': AGENT,\n            'Content-type': 'application/x-www-form-urlencoded',\n            'Accept': 'application/json',\n            }\n\n    # Hack module params to have the Basic auth params that fetch_url expects\n    module.params['url_username'] = account_sid.replace('\\n', '')\n    module.params['url_password'] = auth_token.replace('\\n', '')\n\n    return fetch_url(module, URI, data=encoded_data, headers=headers)\n\n\n# =======================================\n# Main\n#\n\ndef main():\n\n    module = AnsibleModule(\n        argument_spec=dict(\n            account_sid=dict(required=True),\n            auth_token=dict(required=True, no_log=True),\n            msg=dict(required=True),\n            from_number=dict(required=True),\n            to_number=dict(required=True),\n            media_url=dict(default=None, required=False),\n        ),\n        supports_check_mode=True\n    )\n\n    account_sid = module.params['account_sid']\n    auth_token = module.params['auth_token']\n    msg = module.params['msg']\n    from_number = module.params['from_number']\n    to_number = module.params['to_number']\n    media_url = module.params['media_url']\n\n    if not isinstance(to_number, list):\n        to_number = [to_number]\n\n    for number in to_number:\n        r, info = post_twilio_api(module, account_sid, auth_token, msg,\n                from_number, number, media_url)\n        if info['status'] != 200:\n            module.fail_json(msg=\"unable to send message to %s\" % number)\n\n    module.exit_json(msg=msg, changed=False)\n\n# import module snippets\nfrom ansible.module_utils.basic import *\nfrom ansible.module_utils.urls import *\nif __name__ == '__main__':\n    main()\n", "path": "notification/twilio.py"}], "after_files": [{"content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n# (c) 2015, Matt Makai <matthew.makai@gmail.com>\n#\n# This file is part of Ansible\n#\n# Ansible is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# Ansible is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.\n\nDOCUMENTATION = '''\n---\nversion_added: \"1.6\"\nmodule: twilio\nshort_description: Sends a text message to a mobile phone through Twilio.\ndescription:\n   - Sends a text message to a phone number through the Twilio messaging API.\nnotes:\n   - This module is non-idempotent because it sends an email through the\n     external API. It is idempotent only in the case that the module fails.\n   - Like the other notification modules, this one requires an external\n     dependency to work. In this case, you'll need a Twilio account with\n     a purchased or verified phone number to send the text message.\noptions:\n  account_sid:\n    description:\n      user's Twilio account token found on the account page\n    required: true\n  auth_token:\n    description: user's Twilio authentication token\n    required: true\n  msg:\n    description:\n      the body of the text message\n    required: true\n  to_number:\n    description:\n      one or more phone numbers to send the text message to,\n      format +15551112222\n    required: true\n  from_number:\n    description:\n      the Twilio number to send the text message from, format +15551112222\n    required: true\n  media_url:\n    description:\n      a URL with a picture, video or sound clip to send with an MMS\n      (multimedia message) instead of a plain SMS\n    required: false\n\nauthor: \"Matt Makai (@makaimc)\"\n'''\n\nEXAMPLES = '''\n# send an SMS about the build status to (555) 303 5681\n# note: replace account_sid and auth_token values with your credentials\n# and you have to have the 'from_number' on your Twilio account\n- twilio:\n    msg: \"All servers with webserver role are now configured.\"\n    account_sid: \"ACXXXXXXXXXXXXXXXXX\"\n    auth_token: \"ACXXXXXXXXXXXXXXXXX\"\n    from_number: \"+15552014545\"\n    to_number: \"+15553035681\"\n  delegate_to: localhost\n\n# send an SMS to multiple phone numbers about the deployment\n# note: replace account_sid and auth_token values with your credentials\n# and you have to have the 'from_number' on your Twilio account\n- twilio:\n    msg: \"This server's configuration is now complete.\"\n    account_sid: \"ACXXXXXXXXXXXXXXXXX\"\n    auth_token: \"ACXXXXXXXXXXXXXXXXX\"\n    from_number: \"+15553258899\"\n    to_number:\n      - \"+15551113232\"\n      - \"+12025551235\"\n      - \"+19735559010\"\n  delegate_to: localhost\n\n# send an MMS to a single recipient with an update on the deployment\n# and an image of the results\n# note: replace account_sid and auth_token values with your credentials\n# and you have to have the 'from_number' on your Twilio account\n- twilio:\n    msg: \"Deployment complete!\"\n    account_sid: \"ACXXXXXXXXXXXXXXXXX\"\n    auth_token: \"ACXXXXXXXXXXXXXXXXX\"\n    from_number: \"+15552014545\"\n    to_number: \"+15553035681\"\n    media_url: \"https://demo.twilio.com/logo.png\"\n  delegate_to: localhost\n'''\n\n# =======================================\n# twilio module support methods\n#\nimport urllib\n\n\ndef post_twilio_api(module, account_sid, auth_token, msg, from_number,\n                    to_number, media_url=None):\n    URI = \"https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json\" \\\n        % (account_sid,)\n    AGENT = \"Ansible\"\n\n    data = {'From':from_number, 'To':to_number, 'Body':msg}\n    if media_url:\n        data['MediaUrl'] = media_url\n    encoded_data = urllib.urlencode(data)\n\n    headers = {'User-Agent': AGENT,\n            'Content-type': 'application/x-www-form-urlencoded',\n            'Accept': 'application/json',\n            }\n\n    # Hack module params to have the Basic auth params that fetch_url expects\n    module.params['url_username'] = account_sid.replace('\\n', '')\n    module.params['url_password'] = auth_token.replace('\\n', '')\n\n    return fetch_url(module, URI, data=encoded_data, headers=headers)\n\n\n# =======================================\n# Main\n#\n\ndef main():\n\n    module = AnsibleModule(\n        argument_spec=dict(\n            account_sid=dict(required=True),\n            auth_token=dict(required=True, no_log=True),\n            msg=dict(required=True),\n            from_number=dict(required=True),\n            to_number=dict(required=True),\n            media_url=dict(default=None, required=False),\n        ),\n        supports_check_mode=True\n    )\n\n    account_sid = module.params['account_sid']\n    auth_token = module.params['auth_token']\n    msg = module.params['msg']\n    from_number = module.params['from_number']\n    to_number = module.params['to_number']\n    media_url = module.params['media_url']\n\n    if not isinstance(to_number, list):\n        to_number = [to_number]\n\n    for number in to_number:\n        r, info = post_twilio_api(module, account_sid, auth_token, msg,\n                from_number, number, media_url)\n        if info['status'] not in [200, 201]:\n            body_message = \"unknown error\"\n            if 'body' in info:\n                body = json.loads(info['body'])\n                body_message = body['message']\n            module.fail_json(msg=\"unable to send message to %s: %s\" % (number, body_message))\n\n    module.exit_json(msg=msg, changed=False)\n\n# import module snippets\nfrom ansible.module_utils.basic import *\nfrom ansible.module_utils.urls import *\nif __name__ == '__main__':\n    main()\n", "path": "notification/twilio.py"}]}