phpsymfonymailtoemail-client

DraftEmail removing bcc from email


We used to have simple mailto: links to provide users a simple way to open a new draft email with the relevant emails directly filled in.

The issue is that there is a limit to the length of href supported by such links (about 2000 chars), and sometimes we'll need more than that.

So to avoid this issue, I'm shifting to a server-side solution by building a new DraftEmail and just send it in my Response after a .toString().

It works fine as long as the emails are provided in the 'to' and 'cc' fields, but the 'bcc' field doesn't work.

It seems to be on purpose :

https://github.com/symfony/symfony/blob/7.3/src/Symfony/Component/Mime/DraftEmail.php

From what I understand, it seems related to the fact that the bcc should not be in the message but in the envelope. Ok, but then what would be a simple way to do what I'm attempting to do? Because as far as I understand, the envelope is used to send the message, but I don't want to send the message, I just want to create it, the sending is handled by the email client.

Another issue is that unlike mailto: links, a DraftEmail doesn't seem to add the signature of the user, I assume it's because it's an external file and not a new message or a reply, but that's an issue as well.

Are there alternatives in symfony to mailto: links that does the same thing as far as signatures and bcc recipients are concerned, while not having the length limitation?

Thank you for your help


Solution

  • Create a custom DraftEmail class that overrides getPreparedHeaders to retain Bcc.

    use Symfony\Component\Mime\DraftEmail;
    use Symfony\Component\Mime\Header\Headers;
    
    class CustomDraftEmail extends DraftEmail
    {
        public function getPreparedHeaders(): Headers
        {
            $headers = clone $this->getHeaders();
            if (!$headers->has('MIME-Version')) {
                $headers->addTextHeader('MIME-Version', '1.0');
            }
            // Do NOT remove Bcc headers
            return $headers;
        }
    }
    

    Then use the CustomDraftEmail class to create a draft email and include Bcc recipients in the MIME message.

    use App\Mail\CustomDraftEmail;
    use Symfony\Component\HttpFoundation\Response;
    
    $email = (new CustomDraftEmail())
        ->to('recipient@example.com')
        ->cc('cc@example.com')
        ->bcc('bcc@example.com')
        ->subject('Test Draft Email')
        ->text('This is the email body.');
    
    $response = new Response($email->toString());
    $response->headers->set('Content-Type', 'text/plain'); // Adjust based on delivery method
    return $response;
    

    ------ Edits
    This may be not matching your exact needs but, this is how we fixed the issue.
    Like @chris-haas pointed it out, this solution's limitation is a lack of automatic signatures. We mitigated it by appending a placeholder signature to the email body programmatically. (Another alternative can be to Instruct users to add their signature manually after opening the .eml file in their email client):

    Create a controller :

    use App\Mail\CustomDraftEmail;
    use Symfony\Component\HttpFoundation\Response;
    use Symfony\Component\HttpFoundation\ResponseHeaderBag;
    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
    
    class EmailController extends AbstractController
    {
        public function createDraftEmail(): Response
        {
            $email = (new CustomDraftEmail())
                ->to('recipient@example.com')
                ->cc('cc@example.com')
                ->bcc('bcc@example.com')
                ->subject('Test Draft Email')
                ->text("The email body.\n\n-- \nYour Name"); // Here the signature is added
    
            $response = new Response($email->toString());
            $disposition = $response->headers->makeDisposition(
                ResponseHeaderBag::DISPOSITION_ATTACHMENT,
                'draft-email.eml'
            );
            $response->headers->set('Content-Type', 'message/rfc822');
            $response->headers->set('Content-Disposition', $disposition);
    
            return $response;
        }
    }
    

    When the user clicks a link to this endpoint, their browser will download a .eml file.