Skip to content

Commit

Permalink
feature symfony#44311 [Mime] add DraftEmail (kbond)
Browse files Browse the repository at this point in the history
This PR was squashed before being merged into the 6.1 branch.

Discussion
----------

[Mime] add DraftEmail

| Q             | A
| ------------- | ---
| Branch?       | 6.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | n/a
| License       | MIT
| Doc PR        | todo

I've had the need to create "draft" emails pre-filled with content/attachments. User's can then download these as a `.eml`, open with their email client, manipulate, then send. Thought I'd share my solution to see if this is something that would be acceptable in core.

Only needed a few minor adjustments to `Email` that I wrapped up into an `DraftEmail` object:
1. Add `X-Unsent: 1` header (this marks the email as "draft" for clients that support this)
2. Allow no From/To (user can add with their client)
3. Remove Message-ID/Date headers (these will be added by the client)

Usage:

```php
$content = (new DraftEmail()
    ->html($twig->render(...))
    ->attach(...)
    ->toString()
;

$response = new Response($message->toString());
$contentDisposition = $response->headers->makeDisposition(
    ResponseHeaderBag::DISPOSITION_ATTACHMENT,
    'download.eml'
);
$response->headers->set('Content-Type', 'message/rfc822');
$response->headers->set('Content-Disposition', $contentDisposition);
```

Commits
-------

5d6b4a0 [Mime] add DraftEmail
  • Loading branch information
fabpot committed Dec 22, 2021
2 parents 4b598f4 + 5d6b4a0 commit 0d6e859
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 3 deletions.
45 changes: 45 additions & 0 deletions src/Symfony/Component/Mime/DraftEmail.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Mime;

use Symfony\Component\Mime\Header\Headers;
use Symfony\Component\Mime\Part\AbstractPart;

/**
* @author Kevin Bond <[email protected]>
*/
class DraftEmail extends Email
{
public function __construct(Headers $headers = null, AbstractPart $body = null)
{
parent::__construct($headers, $body);

$this->getHeaders()->addTextHeader('X-Unsent', '1');
}

/**
* Override default behavior as draft emails do not require From/Sender/Date/Message-ID headers.
* These are added by the client that actually sends the email.
*/
public function getPreparedHeaders(): Headers
{
$headers = clone $this->getHeaders();

if (!$headers->has('MIME-Version')) {
$headers->addTextHeader('MIME-Version', '1.0');
}

$headers->remove('Bcc');

return $headers;
}
}
15 changes: 12 additions & 3 deletions src/Symfony/Component/Mime/Email.php
Original file line number Diff line number Diff line change
Expand Up @@ -386,13 +386,22 @@ public function getBody(): AbstractPart

public function ensureValidity()
{
if (null === $this->text && null === $this->html && !$this->attachments) {
throw new LogicException('A message must have a text or an HTML part or attachments.');
$this->ensureBodyValid();

if ('1' === $this->getHeaders()->getHeaderBody('X-Unsent')) {
throw new LogicException('Cannot send messages marked as "draft".');
}

parent::ensureValidity();
}

private function ensureBodyValid(): void
{
if (null === $this->text && null === $this->html && !$this->attachments) {
throw new LogicException('A message must have a text or an HTML part or attachments.');
}
}

/**
* Generates an AbstractPart based on the raw body of a message.
*
Expand All @@ -415,7 +424,7 @@ public function ensureValidity()
*/
private function generateBody(): AbstractPart
{
$this->ensureValidity();
$this->ensureBodyValid();

[$htmlPart, $attachmentParts, $inlineParts] = $this->prepareParts();

Expand Down
58 changes: 58 additions & 0 deletions src/Symfony/Component/Mime/Tests/DraftEmailTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Mime\Tests;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Mime\DraftEmail;
use Symfony\Component\Mime\Exception\LogicException;

/**
* @author Kevin Bond <[email protected]>
*/
final class DraftEmailTest extends TestCase
{
public function testCanHaveJustBody()
{
$email = (new DraftEmail())->text('some text')->toString();

$this->assertStringContainsString('some text', $email);
$this->assertStringContainsString('MIME-Version: 1.0', $email);
$this->assertStringContainsString('X-Unsent: 1', $email);
}

public function testBccIsRemoved()
{
$email = (new DraftEmail())->text('some text')->bcc('[email protected]')->toString();

$this->assertStringNotContainsString('[email protected]', $email);
}

public function testMustHaveBody()
{
$this->expectException(LogicException::class);

(new DraftEmail())->toString();
}

public function testEnsureValidityAlwaysFails()
{
$email = (new DraftEmail())
->to('[email protected]')
->from('[email protected]')
->text('some text')
;

$this->expectException(LogicException::class);

$email->ensureValidity();
}
}

0 comments on commit 0d6e859

Please sign in to comment.