Skip to content

Commit 212fcb1

Browse files
author
David McGuire
committed
Merge branch 'master' of github.com:sendgrid/sendgrid-python
2 parents 008ecaf + 3cc3059 commit 212fcb1

11 files changed

Lines changed: 407 additions & 207 deletions

File tree

.travis.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
language: python
2+
python:
3+
- "2.6"
4+
- "2.7"
5+
- "3.2"
6+
install:
7+
- python setup.py -q install
8+
script:
9+
- python setup.py test

README.md

Lines changed: 148 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
[![Build Status](https://travis-ci.org/sendgrid/sendgrid-python.png?branch=master)](https://travis-ci.org/sendgrid/sendgrid-python)
2+
13
# sendgrid-python #
24
This library allows you to quickly and easily send emails through SendGrid using Python.
35

@@ -12,69 +14,189 @@ Using Github:
1214
git clone git@github.com:sendgrid/sendgrid-python.git
1315
```
1416

15-
Using Pypi:
17+
Using PyPI:
1618

1719
```
18-
easy_install sendgrid-python
20+
easy_install sendgrid
1921
```
2022

2123
## SendGrid APIs ##
22-
SendGrid provides two methods of sending email: the Web API, and SMTP API. SendGrid recommends using the SMTP API for sending emails.
23-
For an explanation of the benefits of each, refer to http://docs.sendgrid.com/documentation/get-started/integrate/examples/smtp-vs-rest/.
24+
SendGrid provides two methods of sending email: the Web API, and SMTP API. SendGrid recommends using the SMTP API for sending emails, but the Web API has less communication overhead. For an explanation of the benefits of each, refer to http://docs.sendgrid.com/documentation/get-started/integrate/examples/smtp-vs-rest/.
2425

2526
This library implements a common interface to make it very easy to use either API.
2627

2728
## Mail Pre-Usage ##
2829

29-
Before we begin using the library, its important to understand a few things about the library architecture...
30+
Before we begin using the library, its important to understand a few things about the library architecture:
3031

3132
* Sending an email is as simple as :
3233
1. Creating a SendGrid Instance
3334
1. Creating a SendGrid Mail object, and setting its data
34-
1. Sending the mail using either SMTP API or Web API.
35+
1. Sending the mail using either SMTP API or Web API
3536

3637
## Mail Usage ##
3738

3839
```python
3940
import sendgrid
4041

42+
# make a secure connection to SendGrid
4143
s = sendgrid.Sendgrid('username', 'password', secure=True)
42-
message = sendgrid.Message("from@mydomain.com", "subject", "plain body", "<b>Html here</b>")
44+
45+
# make a message object
46+
message = sendgrid.Message("from@mydomain.com", "message subject", "plaintext message body",
47+
"<p>HTML message body</p>")
48+
# add a recipient
4349
message.add_to("someone@example.com", "John Doe")
4450

51+
# use the Web API to send your message
4552
s.web.send(message)
4653
```
4754

48-
Or
55+
Or change the last line to use the SMTP API instead:
56+
57+
```python
58+
# use the SMTP API to send your message
59+
s.smtp.send(message)
60+
```
61+
62+
To add a 'name' to the From address, you can pass the first parameter to sendgrid.Message() as a tuple:
63+
```python
64+
message = sendgrid.Message(("from@mydomain.com","My Domain"), "message subject", "plaintext body",
65+
"<p>HTML body</p>")
66+
```
67+
68+
To add a Reply-To address, you can call the message.set_replyto() method:
69+
```python
70+
message = sendgrid.Message(("from@mydomain.com","My Domain"), "message subject", "plaintext body",
71+
"<p>HTML body</p>")
72+
message.set_replyto("reply@mydomain.com")
73+
```
74+
Note: Reply-To requires v0.1.3 or higher
75+
76+
### Adding Recipients ###
77+
78+
Using the message.add_to() method, you can add recipient email address (optionally with names), but you can also add CC/BCC recipient addresses (without names) using message.add_cc() and message.add_bcc().
79+
80+
Note: Only the SMTP API supports CC at this time, though we have code and hooks in place for the Web API implementation of this library for future use.
81+
82+
Both the Web API and SMTP API support BCC.
83+
84+
The message.add_cc() and message.add_bcc() calls support passing a single address, or a list of addresses, as shown in the examples below.
4985

5086
```python
87+
message = sendgrid.Message("from@mydomain.com", "message subject", "plaintext message body",
88+
"<p>HTML message body</p>")
89+
90+
# add a To: recipient with a name
91+
message.add_to("someone1@example.com", "John Doe")
92+
93+
# add a To: recipient without a name
94+
message.add_to("someone8@example.com")
95+
96+
# add several To: recipients without names
97+
message.add_to(["someone9@example.com", "someone10@example.com"])
98+
99+
# add several To: recipients without names
100+
# note: count of assigned names must match the count of email addresses
101+
message.add_to(["someone11@example.com", "someone12@example.com"], ["John Smith", "Jane Smith"])
102+
103+
# add a single CC: recipient by passing a string, SMTP API only
104+
message.add_cc("someone2@example.com")
105+
106+
# add several CC: recipients by passing a list, SMTP API only
107+
message.add_cc(["someone3@example.com","someone4@example.com"])
108+
109+
# add a single BCC: recipient by passing a string
110+
message.add_bcc("someone5@example.com")
111+
112+
# add several BCC: recipients by passing a list
113+
message.add_bcc(["someone6@example.com","someone7@example.com"])
114+
115+
# send message to To, CC and BCC recipients using SMTP API
51116
s.smtp.send(message)
117+
118+
# send message to To and BCC recipients using Web API (no CC support)
119+
s.web.send(message)
120+
```
121+
Note: Using CC/BCC with SMTP API requires v0.1.3 or higher
122+
123+
124+
## Using Attachments ###
125+
126+
Attaching files to your message uses the message.add_attachment() method. This method takes two parameters, the intended name of the attachment you want your recipients to see, and the full file system path to the file. Note: File attachments are limited to 7 MB per file, and your total message size must be under 20MB.
127+
128+
```python
129+
message = sendgrid.Message("from@mydomain.com", "subject", "plain body", "<b>Html here</b>")
130+
message.add_attachment("output_filename.doc", "/path/to/input_filename.doc")
52131
```
53132

54-
### Using Categories ###
133+
You can chain several file attachments together, provided you follow the restrictions of 7MB per file and a total size of 20MB or less per message.
55134

56-
Categories are used to group email statistics provided by SendGrid.
135+
```python
136+
message.add_attachment("output_file1.txt", "/path/to/file1.txt").add_attachment("output_file2.txt", "/path/to/file2.txt")
137+
```
138+
139+
A common problem with file attachments is that the second parameter does not exist as a file, in which case the library will attach a 0-byte blank file. Here's a simple check to assist you:
140+
141+
```python
142+
import sendgrid
143+
import os
144+
145+
s = sendgrid.Sendgrid('username', 'password', secure=True)
146+
message = sendgrid.Message("from@mydomain.com", "message subject", "plaintext message body", "<p>HTML message body</p>")
147+
message.add_to("someone@example.com", "John Doe")
148+
if os.path.isfile("/path/to/file1.txt"):
149+
message.add_attachment("file.txt", "/path/to/file1.txt")
150+
s.web.send(message)
151+
```
152+
153+
An optional third parameter can be passed to the message.add_attachment() call which lets you specify a Content-ID header for each file. The Content-ID is used to reference attached files (typically images) within the HTML message. For example:
154+
155+
```python
156+
message = sendgrid.Message("from@mydomain.com", "message subject",
157+
"I have attached my picture, I hope you like it",
158+
"<p>Here is my inline picture<br><img src=\"cid:picture1\"><br>I hope you like it.</p>")
159+
message.add_to("someone@example.com", "John Doe")
160+
161+
message.add_attachment("my_picture.png", "/path/to/my_picture.png", "picture1")
162+
s.web.send(message)
163+
```
57164

58-
To use a category, simply set the category name. Note: there is a maximum of 10 categories per email.
165+
166+
## Using Categories ###
167+
168+
You can mark messages with optional categories to give better visibility to email statistics (opens, clicks, etc.). You can add up to 10 categories per email message. You can read more about Categories here: http://docs.sendgrid.com/documentation/delivery-metrics/categories/
169+
170+
To add categories to your message, use the message.add_category() method and pass a list of one or more category names. SendGrid will begin tracking statistics with these category names if the category name is new, or aggregate statistics for existing category names.
59171

60172
```python
61173
message = sendgrid.Message("from@mydomain.com", "subject", "plain body", "<b>Html here</b>")
62174
message.add_category(["Category 1", "Category 2"])
63175
```
64176

65177

66-
### Using Attachments ###
178+
## Using Unique Arguments ###
179+
180+
Unique Arguments are used for tracking purposes on the message, and can be seen in the Email Activity screen on your account dashboard or through the Event API. Use the message.add_unique_argument() method, which takes two parameters, a key and a value. To pass multiple keys/values, use message.add_unique_arguments() (note the plural method name) and pass a dictionary of key/value pairs. More information can be found here: http://docs.sendgrid.com/documentation/api/smtp-api/developers-guide/unique-arguments/
181+
182+
```python
183+
message = sendgrid.Message("from@mydomain.com", "subject", "plain body", "<b>Html here</b>")
184+
# set 'Customer' to a value of 'Someone'
185+
message.add_unique_argument("Customer", "Someone")
186+
```
67187

68-
File attachments are limited to 7 MB per file.
188+
Alternately, you can pass a dict parameter and add multiple arguments using message.add_unique_arguments() like this:
69189

70190
```python
71191
message = sendgrid.Message("from@mydomain.com", "subject", "plain body", "<b>Html here</b>")
72-
message.add_attachment("file1.doc", "/path/to/file.doc").add_attachment("file2.nfo", "File 2 content")
192+
# set multiple unique arguments for a message
193+
message.add_unique_arguments({"customerAccountNumber": "55555", "activationAttempt": "1"})
73194
```
74195

75-
### Using Substitutions ###
76196

77-
Substitutions can be used to customize multi-recipient emails, and tailor them for the user
197+
## Using Substitutions ###
198+
199+
SendGrid also allows you to send multi-recipient messages with unique information per recipient. This is commonly used for sending unique URLs or codes to a list of recipients in a single batch. You simply expand the data you pass to the message.add_to() method like the example below. You can read more about Substitutions here: http://docs.sendgrid.com/documentation/api/smtp-api/developers-guide/substitution-tags/
78200

79201
```python
80202
message = sendgrid.Message("from@mydomain.com", "subject", "Hello %name%, your code is %code%", "<b>Hello %name%, your code is %code%</b>")
@@ -88,7 +210,7 @@ message.add_to(
88210

89211
### Using Sections ###
90212

91-
Sections can be used to further customize messages for the end users. A section is only useful in conjunction with a substition value.
213+
Used in conjunction with Substitutions, Sections can be used to further customize messages for the end users, and acts like a second tier of substitution data. You can use message.set_section() to add a single section, or a pluralized message.set_sections() method to add several sections. You can read more about using Sections here: http://docs.sendgrid.com/documentation/api/smtp-api/developers-guide/section-tags/
92214

93215
```python
94216
message = sendgrid.Message("from@mydomain.com", "subject", "Hello %name%, you work at %place%",
@@ -97,34 +219,31 @@ message.add_to(
97219
{
98220
'example1@example.com': {'%name%': 'Name 1', '%place%': '%home%'},
99221
'example2@example.com': {'%name%': 'Name 2', '%place%': '%office%'},
222+
'example3@example.com': {'%name%': 'Name 3', '%place%': '%office%'},
100223
}
101224
).set_sections({"%office%": "an office", "%home%": "your house"})
102225
```
103226

104-
### Using Unique Arguments ###
105227

106-
Unique Arguments are used for tracking purposes
228+
## Using Custom Headers ###
229+
230+
Custom SMTP headers can be added as necessary using the message.add_header() method.
107231

108232
```python
109233
message = sendgrid.Message("from@mydomain.com", "subject", "plain body", "<b>Html here</b>")
110-
message.add_unique_argument("Customer", "Someone")
234+
message.add_header("X-Mailer", "MyApp")
111235
```
112236

113-
### Using Filter Settings ###
114237

115-
Filter Settings are used to enable and disable apps, and to pass parameters to those apps.
238+
## Using Filter Settings ###
239+
240+
Filter Settings are used to enable and disable apps, and to pass parameters to those apps. You can read more here: http://docs.sendgrid.com/documentation/api/smtp-api/filter-settings/
241+
Here's an example of passing content to the 'footer' app:
116242

117243
```python
118244
message = sendgrid.Message("from@mydomain.com", "subject", "plain body", "<b>Html here</b>")
119245
message.add_filter_setting("footer", "text/plain", "Here is a plain text footer")
120246
message.add_filter_setting("footer", "text/html", "<p style='color:red;'>Here is an HTML footer</p>")
121247
```
122248

123-
### Using Headers ###
124249

125-
Custom headers can be added as necessary.
126-
127-
```python
128-
message = sendgrid.Message("from@mydomain.com", "subject", "plain body", "<b>Html here</b>")
129-
message.add_header("X-Mailer", "MyApp")
130-
```

sendgrid/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33

44
del sendgrid, message
55

6-
__version__ = "0.1.0"
7-
version_info = (0, 1, 0)
6+
__version__ = "0.1.3"
7+
version_info = (0, 1, 3)

sendgrid/header.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,74 +3,83 @@
33
except ImportError:
44
import simplejson as json
55

6+
67
class SmtpApiHeader(object):
78
def __init__(self):
89
self.data = {}
910

10-
1111
def add_to(self, to):
12-
if not self.data.has_key('to'):
12+
if 'to' not in self.data:
1313
self.data['to'] = []
1414
if type(to) is str:
1515
self.data['to'] += [to]
1616
else:
1717
self.data['to'] += to
1818

19+
def add_cc(self, cc):
20+
if 'cc' not in self.data:
21+
self.data['cc'] = []
22+
if type(cc) is str:
23+
self.data['cc'] += [cc]
24+
else:
25+
self.data['cc'] += cc
26+
27+
def add_bcc(self, bcc):
28+
if 'bcc' not in self.data:
29+
self.data['bcc'] = []
30+
if type(bcc) is str:
31+
self.data['bcc'] += [bcc]
32+
else:
33+
self.data['bcc'] += bcc
34+
35+
def set_replyto(self, replyto):
36+
self.data['reply_to'] = replyto
1937

2038
def add_sub_val(self, var, val):
21-
if not self.data.has_key('sub'):
39+
if 'sub' not in self.data:
2240
self.data['sub'] = {}
2341
if type(val) is str:
2442
self.data['sub'][var] = [val]
2543
else:
2644
self.data['sub'][var] = val
2745

28-
2946
def set_unique_args(self, val):
3047
if type(val) is dict:
3148
self.data['unique_args'] = val
3249

33-
3450
def add_unique_arg(self, key, val):
35-
if not self.data.has_key('unique_args'):
51+
if 'unique_args' not in self.data:
3652
self.data['unique_args'] = {}
3753
self.data['unique_args'][key] = val
3854

39-
4055
def set_category(self, cat):
4156
self.data['category'] = [cat]
4257

43-
4458
def add_category(self, cat):
45-
if not self.data.has_key('category'):
59+
if 'category' not in self.data:
4660
self.data['category'] = []
4761
self.data['category'].append(cat)
4862

49-
5063
def add_section(self, key, section):
51-
if not self.data.has_key('section'):
64+
if 'section' not in self.data:
5265
self.data['section'] = {}
5366
self.data['section'][key] = section
5467

55-
5668
def set_section(self, val):
5769
self.data['section'] = val
5870

59-
6071
def add_filter_setting(self, fltr, setting, val):
61-
if not self.data.has_key('filters'):
72+
if 'filters' not in self.data:
6273
self.data['filters'] = {}
63-
if not self.data['filters'].has_key(fltr):
74+
if fltr not in self.data:
6475
self.data['filters'][fltr] = {}
65-
if not self.data['filters'][fltr].has_key('settings'):
76+
if 'settings' not in self.data['filters'][fltr]:
6677
self.data['filters'][fltr]['settings'] = {}
6778
self.data['filters'][fltr]['settings'][setting] = val
6879

69-
7080
def as_json(self):
7181
return json.dumps(self.data)
7282

73-
7483
def as_string(self):
7584
str = 'X-SMTPAPI: %s' % self.as_json()
76-
return str
85+
return str

0 commit comments

Comments
 (0)