Repository: sendgrid/sendgrid-python

Issue:
JSON quoted comma not ignored
#### Issue Summary

I'm using a python script to send emails. It mostly works.  Comma embedded in quotes are causing the submission to fail.

#### Steps to Reproduce

The input is a CSV file.

"Joe User",addr1@example.com,54321
"User, Joe",addr2@example.com,55555
The second line fails.

Python correctly parses the line and formats it as JSON, but it fails on submission. Apparently the quotes on name field are ignored and sees the embedded comma as a delimiter. It then uses User as the name and Joe as the email address and fails.

Is this a known bug? Is there a work-around?


#### Technical details:

* sendgrid-python 5.3.0
* Python Version: 2.7.3

Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/sendgrid/sendgrid-python/pull/618?src=pr&el=h1) Report
> Merging [#618](https://codecov.io/gh/sendgrid/sendgrid-python/pull/618?src=pr&el=desc) into [master](https://codecov.io/gh/sendgrid/sendgrid-python/commit/84f7cf258f77f179dce0ef3bee8dc3b90f4af2f3?src=pr&el=desc) will **decrease** coverage by `0.23%`.
> The diff coverage is `66.66%`.

[![Impacted file tree graph](https://codecov.io/gh/sendgrid/sendgrid-python/pull/618/graphs/tree.svg?width=650&token=Yq0yTs1Nfq&height=150&src=pr)](https://codecov.io/gh/sendgrid/sendgrid-python/pull/618?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #618      +/-   ##
==========================================
- Coverage   84.77%   84.54%   -0.24%     
==========================================
  Files          35       35              
  Lines        1156     1171      +15     
  Branches      172      175       +3     
==========================================
+ Hits          980      990      +10     
- Misses         90       93       +3     
- Partials       86       88       +2
```


| [Impacted Files](https://codecov.io/gh/sendgrid/sendgrid-python/pull/618?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [sendgrid/helpers/mail/email.py](https://codecov.io/gh/sendgrid/sendgrid-python/pull/618/diff?src=pr&el=tree#diff-c2VuZGdyaWQvaGVscGVycy9tYWlsL2VtYWlsLnB5) | `88.46% <66.66%> (-8.84%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/sendgrid/sendgrid-python/pull/618?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/sendgrid/sendgrid-python/pull/618?src=pr&el=footer). Last update [84f7cf2...dc9b241](https://codecov.io/gh/sendgrid/sendgrid-python/pull/618?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

thinkingserious: @cmccandless,

Could you please merge this agains [this branch](https://github.com/sendgrid/sendgrid-python/tree/v4)? Thanks!

With Best Regards,

Elmer

Patch:
diff --git a/sendgrid/helpers/mail/email.py b/sendgrid/helpers/mail/email.py
index 0cc6339..432c980 100644
--- a/sendgrid/helpers/mail/email.py
+++ b/sendgrid/helpers/mail/email.py
@@ -3,6 +3,20 @@ try:
 except ImportError:
     import email.utils as rfc822
 
+import sys
+if sys.version_info[:3] >= (3, 5, 0):
+    import html
+    html_entity_decode = html.unescape
+else:
+    try:
+        # Python 2.6-2.7
+        from HTMLParser import HTMLParser
+    except ImportError:
+        # Python < 3.5
+        from html.parser import HTMLParser
+    __html_parser__ = HTMLParser()
+    html_entity_decode = __html_parser__.unescape
+
 
 class Email(object):
     """An email address with an optional name."""
@@ -35,6 +49,14 @@ class Email(object):
 
     @name.setter
     def name(self, value):
+        if not (value is None or isinstance(value, str)):
+            raise TypeError('name must be of type string.')
+
+        # Escape common CSV delimiters as workaround for
+        # https://github.com/sendgrid/sendgrid-python/issues/578
+        if value is not None and (',' in value or ';' in value):
+            value = html_entity_decode(value)
+            value = '"' + value + '"'
         self._name = value
 
     @property


Test patch:
diff --git a/test/test_email.py b/test/test_email.py
index 902c59d..0604ef2 100644
--- a/test/test_email.py
+++ b/test/test_email.py
@@ -58,3 +58,10 @@ class TestEmailObject(unittest.TestCase):
         email.email = address
 
         self.assertEqual(email.email, address)
+
+    def test_add_name_with_comma(self):
+        email = Email()
+        name = "Name, Some"
+        email.name = name
+
+        self.assertEqual(email.name, '"' + name + '"')