Skip to content

Commit dc9dba2

Browse files
Merge pull request sendgrid#743 from semijoelon/box-file-attach
Added Box attachment example (issue sendgrid#481)
2 parents 62a985c + 187c8fe commit dc9dba2

File tree

2 files changed

+178
-1
lines changed

2 files changed

+178
-1
lines changed

USE_CASES.md

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ This documentation provides examples for specific use cases. Please [open an iss
33
# Table of Contents
44
- [Table of Contents](#table-of-contents)
55
- [Attachments](#attachments)
6+
- [Attaching a File from Box](#attaching-a-file-from-box)
67
- [Kitchen Sink - an example with all settings used](#kitchen-sink)
78
- [Send an Email to a Single Recipient](#send-an-email-to-a-single-recipient)
89
- [Send an Email to Multiple Recipients](#send-an-email-to-multiple-recipients)
@@ -58,6 +59,181 @@ try {
5859
}
5960
```
6061

62+
<a name="box-attachment-example"></a>
63+
# Attaching a File from Box
64+
65+
You can attach a file from [Box](https://www.box.com) to your emails.
66+
Because there is no official Box SDK for PHP, this example requires
67+
[firebase/php-jwt](https://github.com/firebase/php-jwt) to generate a
68+
[JSON Web Token](https://jwt.io) assertion. Before using this code, you should
69+
set up a JWT application on [Box](https://developer.box.com/docs/setting-up-a-jwt-app).
70+
For more information about authenticating with JWT, see
71+
[this page](https://developer.box.com/docs/construct-jwt-claim-manually).
72+
73+
After completing the setup tutorial, you will want to make sure your app’s
74+
configuration settings have at least the following options enabled:
75+
76+
**Application Access**
77+
* Enterprise
78+
79+
**Application Scopes**
80+
* Read all files and folders stored in Box
81+
* Read and write all files and folders stored in Box
82+
* Manage users
83+
84+
**Advanced Features**
85+
* Perform Actions as Users
86+
87+
Remember to reauthorize your app
88+
[here](https://app.box.com/master/settings/openbox) after making any changes to
89+
your app’s JWT scopes.
90+
91+
```php
92+
<?php
93+
94+
// This example assumes you're using Composer for both
95+
// the sendgrid-php library and php-jwt.
96+
97+
require 'vendor/autoload.php';
98+
99+
use \Firebase\JWT\JWT;
100+
101+
$fileOwner = 'email@example.com'; // Replace with the email you use to sign in to Box
102+
$filePath = '/path/to/file.txt'; // Replace with the path on Box to the file you will attach
103+
$boxConfig = json_decode(file_get_contents('/path/to/boxConfig.json')); // Replace with the path to your Box config file. Keep it in a secure location!
104+
105+
$path = explode('/', $filePath);
106+
if (!empty($path[0])){
107+
array_unshift($path, ''); // Adds a blank element to beginning of array in case $filePath does not have a preceding forward slash.
108+
}
109+
110+
$header = array(
111+
'alg' => 'RS256',
112+
'typ' => 'JWT',
113+
'kid' => $boxConfig->boxAppSettings->appAuth->publicKeyID
114+
);
115+
$claims = array(
116+
'iss' => $boxConfig->boxAppSettings->clientID,
117+
'sub' => $boxConfig->enterpriseID,
118+
'box_sub_type' => 'enterprise',
119+
'aud' => 'https://api.box.com/oauth2/token',
120+
'jti' => bin2hex(openssl_random_pseudo_bytes(16)),
121+
'exp' => time() + 50
122+
);
123+
124+
$privateKey = openssl_get_privatekey($boxConfig->boxAppSettings->appAuth->privateKey, $boxConfig->boxAppSettings->appAuth->passphrase);
125+
126+
$assertion = JWT::encode($claims, $privateKey, 'RS256', null, $header);
127+
128+
// Get access token
129+
$url = 'https://api.box.com/oauth2/token';
130+
$data = array(
131+
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
132+
'client_id' => $boxConfig->boxAppSettings->clientID,
133+
'client_secret' => $boxConfig->boxAppSettings->clientSecret,
134+
'assertion' => $assertion
135+
);
136+
$ch = curl_init($url);
137+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
138+
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
139+
$result = json_decode(curl_exec($ch));
140+
curl_close($ch);
141+
$accessToken = $result->access_token;
142+
143+
// Get user ID
144+
$url = 'https://api.box.com/2.0/users';
145+
$ch = curl_init($url);
146+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
147+
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
148+
'Authorization: Bearer '.$accessToken
149+
));
150+
$result = json_decode(curl_exec($ch));
151+
curl_close($ch);
152+
foreach ($result->entries as $entry){
153+
if ($entry->login === $fileOwner){
154+
$userId = $entry->id;
155+
}
156+
}
157+
158+
// Get file ID
159+
$url = 'https://api.box.com/2.0/search';
160+
$data = array(
161+
'query' => urlencode(end($path))
162+
);
163+
$urlEncoded = http_build_query($data);
164+
$ch = curl_init($url.'?'.$urlEncoded);
165+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
166+
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
167+
'Authorization: Bearer '.$accessToken,
168+
'As-User: '.$userId
169+
));
170+
$result = json_decode(curl_exec($ch));
171+
curl_close($ch);
172+
foreach ($result->entries as $entry){
173+
if (count($entry->path_collection->entries) === count($path) -1){
174+
if (count($path) > 2){
175+
// File is located in a subdirectory.
176+
for ($i = 1; $i < (count($path) - 1); $i++){
177+
if ($path[$i] === $entry->path_collection->entries[$i]->name){
178+
$fileId = $entry->id;
179+
}
180+
}
181+
} else {
182+
// File is located in default directory.
183+
$fileId = $entry->id;
184+
}
185+
}
186+
}
187+
188+
if (isset($fileId) && isset($userId)){
189+
// Get file data
190+
$url = 'https://api.box.com/2.0/files/'.$fileId.'/content';
191+
$ch = curl_init($url);
192+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
193+
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
194+
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
195+
'Authorization: Bearer '.$accessToken,
196+
'As-User: '.$userId
197+
));
198+
$result = curl_exec($ch);
199+
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
200+
curl_close($ch);
201+
202+
$attachmentFilename = end($path);
203+
$attachmentContent = base64_encode($result);
204+
$attachmentContentType = $contentType;
205+
206+
$email = new \SendGrid\Mail\Mail();
207+
$email->setFrom("test@example.com", "Example User");
208+
$email->setSubject("Attaching a File from Box");
209+
$email->addTo("test@example.com", "Example User");
210+
$email->addContent("text/plain", "See attached file from Box.");
211+
$email->addContent(
212+
"text/html", "<strong>See attached file from Box.</strong>"
213+
);
214+
215+
$attachment = new \SendGrid\Mail\Attachment();
216+
$attachment->setContent($attachmentContent);
217+
$attachment->setType($attachmentContentType);
218+
$attachment->setFilename($attachmentFilename);
219+
$attachment->setDisposition("attachment");
220+
$attachment->setContentId($attachmentFilename); // Only used if disposition is set to inline
221+
$email->addAttachment($attachment);
222+
223+
$sendgrid = new \SendGrid(getenv('SENDGRID_API_KEY'));
224+
try {
225+
$response = $sendgrid->send($email);
226+
print $response->statusCode() . "\n";
227+
print_r($response->headers());
228+
print $response->body() . "\n";
229+
} catch (Exception $e) {
230+
echo 'Caught exception: '. $e->getMessage() ."\n";
231+
}
232+
} else {
233+
echo "Error: file or owner could not be located\n";
234+
}
235+
```
236+
61237
<a name="kitchen-sink"></a>
62238
# Kitchen Sink - an example with all settings used
63239

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"sendgrid/php-http-client": "~3.9",
1717
"ext-curl": "*",
1818
"ext-json": "*",
19-
"ext-mbstring": "*"
19+
"ext-mbstring": "*",
20+
"ext-openssl": "*"
2021
},
2122
"require-dev": {
2223
"phpunit/phpunit": "^5.7.9 || ^6.4.3",

0 commit comments

Comments
 (0)