Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

All notable changes will be documented in this file

## 2.3.0 - 2022-12-12

- Attachments and inline attachments are now supported.

## 2.2.0 - 2022-09-24

- You can now pass nested arrays, numbers, bools as the payload. Previously, the library only accepted strings. (Thanks [timstl](https://github.com/swiftmade/laravel-sendgrid-notification-channel/pull/7))
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,21 @@ return (new SendGridMessage('Your SendGrid template ID'))

When making a request with sandbox mode enabled, Sendgrid will validate the form, type, and shape of your request. No email will be sent. You can read more about the sandbox mode [here](https://docs.sendgrid.com/for-developers/sending-email/sandbox-mode).

### Attachments

You can attach or embed (inline attachment) files to your messages. `SendGridMessage` object exposes the following methods to help you do that:

- `attach($file, $options)`
- `attachData($data, $name, $options)`
- `embed($file, $options)`
- `embedData($data, $name, $options)`

**Good to know:**

- While using `attachData` and `embedData` you must always pass the `mime` key in the options array.
- You can use the `as` key in the options to change the filename to appears in the email. (e.g. `attach($file, ['as' => 'invoice-3252.pdf'])`)
- `embed` and `embedData` methods will return the ContentID with `cid:` in front (e.g. `embed('avatar.jpg') -> "cid:avatar.jpg"`).

## Changelog

Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.
Expand Down
8 changes: 6 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.8",
"mockery/mockery": "^1.3",
"mockery/mockery": "^1.5",
"orchestra/testbench": "^5.0|^6.0|^7.0",
"phpunit/phpunit": "^8.4|^9.0"
},
"autoload": {
Expand All @@ -34,7 +35,10 @@
},
"scripts": {
"test": "phpunit",
"test:coverage": "phpunit --coverage-text --coverage-clover=coverage.clover"
"test:coverage": "phpunit --coverage-text --coverage-clover=coverage.clover",
"post-autoload-dump": [
"@php vendor/bin/testbench package:discover --ansi"
]
},
"config": {
"sort-packages": true
Expand Down
3 changes: 3 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@
<directory suffix=".php">src/</directory>
</whitelist>
</filter>
<php>
<env name="APP_KEY" value="AckfSECXIvnK5r28GVIWUAxmbBSjTsmF"/>
</php>
</phpunit>
137 changes: 108 additions & 29 deletions src/SendGridMessage.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

namespace NotificationChannels\SendGrid;

use RuntimeException;
use SendGrid\Mail\To;
use SendGrid\Mail\From;
use SendGrid\Mail\Mail;
use SendGrid\Mail\ReplyTo;
use SendGrid\Mail\Attachment;
use Illuminate\Support\Facades\File;

class SendGridMessage
{
Expand Down Expand Up @@ -111,26 +113,116 @@ public function payload($payload)
return $this;
}

public function attach($attachments)
/**
* Attach a file to the message.
*
* array(
* 'as' => 'name.pdf',
* 'mime' => 'application/pdf',
* )
*
* @param string $file
* @param array $options
* @return $this
*/
public function attach($file, array $options = [])
{
/*
$attachments should be an array of individual attachments. content should be base64 encoded.

Example:
$attachments = array(
array(
'content' => base64_encode($content),
'type' => 'application/pdf',
'filename' => 'filename.pdf'
)
if (! isset($options['mime'])) {
$options['mime'] = File::mimeType($file);
}

// TODO: Support "Attachable" and "Attachment" types.

return $this->attachData(
file_get_contents($file),
$file,
$options
);
*/
}

$this->attachments = $attachments;
/**
* Attach in-memory data as an attachment.
*
* @param string $data
* @param string $name
* @param array $options
* @return $this
*/
public function attachData($data, $name, array $options)
{
if (! isset($options['mime'])) {
throw new RuntimeException(
'Cannot predict mimetype of "' . $name . '". '
. 'Provide a valid \'mime\' in $options parameter.'
);
}

$showFilenameAs = isset($options['as'])
? $options['as']
: basename($name);

$attachment = new Attachment(
base64_encode($data),
$options['mime'],
$showFilenameAs,
isset($options['inline']) ? 'inline' : 'attachment'
);

if (isset($options['inline'])) {
$attachment->setContentID($showFilenameAs);
}

$this->attachments[] = $attachment;

return $this;
}

/**
* Add inline attachment from a file in the message and get the CID.
*
* array(
* 'as' => 'name.pdf',
* 'mime' => 'application/pdf',
* )
*
* @param string $file
* @return string
*/
public function embed($file, array $options = [])
{
if (! isset($options['mime'])) {
$options['mime'] = File::mimeType($file);
}

// TODO: Support "Attachable" and "Attachment" types.

return $this->embedData(
file_get_contents($file),
$file,
$options
);
}

/**
* Add inline attachments from in-memory data in the message and get the CID.
*
* @param string $data
* @param string $name
* @param string|null $contentType
* @return string
*/
public function embedData($data, $name, array $options)
{
$this->attachData($data, $name, array_merge(
$options,
['inline' => true]
));

$lastIndex = count($this->attachments) - 1;

return "cid:" . $this->attachments[$lastIndex]->getContentID();
}

/**
* @return Mail
*/
Expand All @@ -152,24 +244,11 @@ public function build(): Mail
$email->addDynamicTemplateData((string) $key, $value);
}

if (is_array($this->attachments) && !empty($this->attachments)) {
foreach ($this->attachments as $attachment) {
$disposition = (isset($attachment['disposition'])) ? strtolower($attachment['disposition']) : "attachment";

$sgAttachment = new Attachment();
$sgAttachment->setType($attachment['type']);
$sgAttachment->setContent($attachment['content']);
$sgAttachment->setDisposition($disposition);
$sgAttachment->setFilename($attachment['filename']);

if ($disposition === "inline") {
$sgAttachment->setContentID($attachment['filename']);
}

$email->addAttachment($sgAttachment);
}
foreach ($this->attachments as $attachment) {
$email->addAttachment($attachment);
}


return $email;
}

Expand Down
1 change: 0 additions & 1 deletion tests/SendGridChannelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use Mockery;
use SendGrid;
use SendGrid\Response;
use PHPUnit\Framework\TestCase;
use Illuminate\Notifications\Notifiable;
use Illuminate\Notifications\Notification;
use NotificationChannels\SendGrid\SendGridChannel;
Expand Down
116 changes: 115 additions & 1 deletion tests/SendGridMessageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace NotificationChannels\SendGrid\Test;

use PHPUnit\Framework\TestCase;
use SendGrid\Mail\Attachment;
use NotificationChannels\SendGrid\SendGridMessage;

class SendGridMessageTest extends TestCase
Expand Down Expand Up @@ -50,4 +50,118 @@ public function testSandboxMode()
'Sandbox mode is disabled in Sendgrid mail settings'
);
}

public function testAttachmentFromPath()
{
$path = __DIR__ . '/fixtures/blank.jpg';

$message = new SendGridMessage('template-id');
$message->attach(__DIR__ . '/fixtures/blank.jpg');

/**
* @var Attachment
*/
$attachment = $message->attachments[0];

// Contents are base64-encoded
$this->assertEquals(
base64_encode(file_get_contents($path)),
$attachment->getContent()
);

$this->assertEquals('blank.jpg', $attachment->getFilename());
$this->assertEquals('image/jpeg', $attachment->getType());
$this->assertEquals('attachment', $attachment->getDisposition());

// Let's test the options array.
$message->attach(__DIR__ . '/fixtures/blank.jpg', [
'as' => 'custom.png',
'mime' => 'image/png',
]);

/**
* @var Attachment
*/
$attachment2 = $message->attachments[1];
$this->assertEquals('custom.png', $attachment2->getFilename());
$this->assertEquals('image/png', $attachment2->getType());
$this->assertEquals('attachment', $attachment2->getDisposition());
}

public function testAttachmentFromData()
{
$path = __DIR__ . '/fixtures/blank.jpg';
$contents = file_get_contents($path);

$message = new SendGridMessage('template-id');
$message->attachData($contents, 'blank.jpg', ['mime' => 'image/jpeg']);

/**
* @var Attachment
*/
$attachment = $message->attachments[0];

// Contents are base64-encoded
$this->assertEquals(
base64_encode($contents),
$attachment->getContent()
);

$this->assertEquals('blank.jpg', $attachment->getFilename());
$this->assertEquals('image/jpeg', $attachment->getType());
$this->assertEquals('attachment', $attachment->getDisposition());
}

public function testEmbeddingFromPath()
{
$path = __DIR__ . '/fixtures/blank.jpg';

$message = new SendGridMessage('template-id');
$contentId = $message->embed(__DIR__ . '/fixtures/blank.jpg');

$this->assertEquals('cid:blank.jpg', $contentId);

/**
* @var Attachment
*/
$attachment = $message->attachments[0];

// Contents are base64-encoded
$this->assertEquals(
base64_encode(file_get_contents($path)),
$attachment->getContent()
);

$this->assertEquals('blank.jpg', $attachment->getFilename());
$this->assertEquals('image/jpeg', $attachment->getType());
$this->assertEquals('inline', $attachment->getDisposition());
$this->assertEquals('blank.jpg', $attachment->getContentID());
}

public function testEmbeddingFromData()
{
$path = __DIR__ . '/fixtures/blank.jpg';
$contents = file_get_contents($path);

$message = new SendGridMessage('template-id');
$contentId = $message->embedData($contents, 'blank.png', ['mime' => 'image/png']);

$this->assertEquals('cid:blank.png', $contentId);

/**
* @var Attachment
*/
$attachment = $message->attachments[0];

// Contents are base64-encoded
$this->assertEquals(
base64_encode(file_get_contents($path)),
$attachment->getContent()
);

$this->assertEquals('blank.png', $attachment->getFilename());
$this->assertEquals('image/png', $attachment->getType());
$this->assertEquals('inline', $attachment->getDisposition());
$this->assertEquals('blank.png', $attachment->getContentID());
}
}
7 changes: 7 additions & 0 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace NotificationChannels\SendGrid\Test;

class TestCase extends \Orchestra\Testbench\TestCase
{
}
Binary file added tests/fixtures/blank.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.