|
| 1 | +# Special Characters Encoding Example |
| 2 | + |
| 3 | +This example demonstrates how the Nylas Python SDK correctly handles special characters (accented letters, unicode characters) in email subjects and message bodies. |
| 4 | + |
| 5 | +## The Problem |
| 6 | + |
| 7 | +Previously, when sending emails with large attachments (>3MB), special characters in the subject line would be incorrectly encoded. For example: |
| 8 | + |
| 9 | +- **Intended Subject:** "De l'idée à la post-prod, sans friction" |
| 10 | +- **What Recipients Saw:** "De l’idée à la post-prod, sans friction" |
| 11 | + |
| 12 | +This issue occurred because the SDK was using `json.dumps()` with the default `ensure_ascii=True` parameter when creating multipart/form-data requests for large attachments. |
| 13 | + |
| 14 | +## The Solution |
| 15 | + |
| 16 | +The SDK now uses `json.dumps(request_body, ensure_ascii=False)` to preserve UTF-8 characters correctly in the JSON payload, ensuring that special characters are displayed properly in recipient inboxes. |
| 17 | + |
| 18 | +## What This Example Demonstrates |
| 19 | + |
| 20 | +1. **Small Messages** - Sending messages with special characters (no attachments) |
| 21 | +2. **Large Messages** - Sending messages with special characters AND large attachments (>3MB) |
| 22 | +3. **Drafts** - Creating drafts with special characters |
| 23 | +4. **International Support** - Handling various international character sets |
| 24 | + |
| 25 | +## Usage |
| 26 | + |
| 27 | +### Prerequisites |
| 28 | + |
| 29 | +1. Install the SDK in development mode: |
| 30 | + ```bash |
| 31 | + cd /path/to/nylas-python |
| 32 | + pip install -e . |
| 33 | + ``` |
| 34 | + |
| 35 | +2. Set up environment variables: |
| 36 | + ```bash |
| 37 | + export NYLAS_API_KEY="your_api_key" |
| 38 | + export NYLAS_GRANT_ID="your_grant_id" |
| 39 | + export RECIPIENT_EMAIL= "[email protected]" |
| 40 | + ``` |
| 41 | + |
| 42 | +### Run the Example |
| 43 | + |
| 44 | +```bash |
| 45 | +python examples/special_characters_demo/special_characters_example.py |
| 46 | +``` |
| 47 | + |
| 48 | +## Test Coverage |
| 49 | + |
| 50 | +This fix is covered by comprehensive tests: |
| 51 | + |
| 52 | +```bash |
| 53 | +# Test the core fix in file_utils |
| 54 | +pytest tests/utils/test_file_utils.py::TestFileUtils::test_build_form_request_with_special_characters |
| 55 | + |
| 56 | +# Test message sending with special characters |
| 57 | +pytest tests/resources/test_messages.py::TestMessage::test_send_message_with_special_characters_in_subject |
| 58 | +pytest tests/resources/test_messages.py::TestMessage::test_send_message_with_special_characters_large_attachment |
| 59 | + |
| 60 | +# Test draft creation with special characters |
| 61 | +pytest tests/resources/test_drafts.py::TestDraft::test_create_draft_with_special_characters_in_subject |
| 62 | +pytest tests/resources/test_drafts.py::TestDraft::test_create_draft_with_special_characters_large_attachment |
| 63 | +``` |
| 64 | + |
| 65 | +## Supported Character Sets |
| 66 | + |
| 67 | +The SDK correctly handles: |
| 68 | + |
| 69 | +- **French:** é, è, ê, à, ù, ç, œ |
| 70 | +- **Spanish:** ñ, á, í, ó, ú, ¿, ¡ |
| 71 | +- **German:** ä, ö, ü, ß |
| 72 | +- **Portuguese:** ã, õ, â, ê |
| 73 | +- **Italian:** à, è, é, ì, ò, ù |
| 74 | +- **Russian:** Cyrillic characters |
| 75 | +- **Japanese:** Hiragana, Katakana, Kanji |
| 76 | +- **Chinese:** Simplified and Traditional characters |
| 77 | +- **Emoji:** 🎉 🎊 🥳 and many more |
| 78 | +- **Special symbols:** €, £, ¥, ©, ®, ™ |
| 79 | + |
| 80 | +## Technical Details |
| 81 | + |
| 82 | +### The Bug |
| 83 | + |
| 84 | +When using multipart/form-data encoding (for large attachments), the message payload was serialized as: |
| 85 | + |
| 86 | +```python |
| 87 | +message_payload = json.dumps(request_body) # Default: ensure_ascii=True |
| 88 | +``` |
| 89 | + |
| 90 | +This caused special characters to be escaped as unicode sequences: |
| 91 | +```json |
| 92 | +{"subject": "De l\u2019id\u00e9e"} |
| 93 | +``` |
| 94 | + |
| 95 | +### The Fix |
| 96 | + |
| 97 | +The payload is now serialized as: |
| 98 | + |
| 99 | +```python |
| 100 | +message_payload = json.dumps(request_body, ensure_ascii=False) |
| 101 | +``` |
| 102 | + |
| 103 | +This preserves the actual UTF-8 characters: |
| 104 | +```json |
| 105 | +{"subject": "De l'idée"} |
| 106 | +``` |
| 107 | + |
| 108 | +The multipart/form-data Content-Type header correctly specifies UTF-8 encoding, ensuring email clients display the characters properly. |
| 109 | + |
| 110 | +## Related Files |
| 111 | + |
| 112 | +- **Core Fix:** `nylas/utils/file_utils.py` - Line 70 |
| 113 | +- **Tests:** `tests/utils/test_file_utils.py`, `tests/resources/test_messages.py`, `tests/resources/test_drafts.py` |
| 114 | +- **Example:** `examples/special_characters_demo/special_characters_example.py` |
| 115 | + |
| 116 | +## Impact |
| 117 | + |
| 118 | +✅ **Before Fix:** Special characters in subjects were garbled when sending emails with large attachments |
| 119 | +✅ **After Fix:** All special characters are correctly preserved and displayed |
| 120 | + |
| 121 | +The fix ensures backwards compatibility - all existing code continues to work without changes. |
0 commit comments