Create PDF attachment from pdf template and send with email without saving attachment

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • czcpf
    Senior Member
    • Aug 2022
    • 160

    Create PDF attachment from pdf template and send with email without saving attachment

    Hello,

    I'm trying to avoid having to save a pdf as a new Attachment before sending the pdf as an attachment to the email. Is this possible?

    Something like:

    PHP Code:
    $contents = file_get_contents('/?entryPoint=pdf&entityType={myEntityType}&entityId ={myEntityId}&templateId={myTemplateId}');​
    $attachmentRepository = $this->recordServiceContainer
    ->get(Attachment::ENTITY_TYPE)
    ->getRepository();​
    $attachment = $attachmentRepository->getNew();
    $attachment->setContents($contents);
    $attachment->set([
    'name' => 'myPdfName',
    'type' => 'application/pdf',
    ]);​
    $email = $this->emailFactory->create();
    $email->setSubject($subject);
    $email->setBody($body);
    $email->addToAddress({toaddress});
    $email->setIsHtml(true);
    $email->addAttachment($attachment);
    $attachmentList = [$attachment];
    $this->emailSender
    ->withAttachments($attachmentList)
    ->send($email);



    Last edited by czcpf; 07-25-2023, 03:23 PM.
  • rabii
    Active Community Member
    • Jun 2016
    • 1250

    #2
    I doubt that this is possible, the reason is sending an email will need an actual file generated by the system, what i suggest is maybe if you have that pdf already generated you can use getCopiedAttachment Method on the Attachment Repository to make a copy of it without storing it in the storage. Not sure if this is what you are intending to do though. Another work around is that you can still generate a new attachment as a pdf in your code and send your email and only then check if email status is sent then delete the new created attachment.
    Last edited by rabii; 07-20-2023, 09:19 AM.
    Rabii
    Web Dev

    Comment

    • czcpf
      Senior Member
      • Aug 2022
      • 160

      #3
      Thanks rabii . I thought about just deleting the attachment afterwords but I don’t believe that also deletes the file from storage. I could delete it with pure php I suppose. The basic idea here was to to save storage since this file is a report that goes out weekly for each account. Over time, and with a lot of accounts, that will add up. There is also the issue with latency if, for example, I’m using non-local storage like an s3 bucket. Having to wait for the file to be written, transmitted, saved, and then retrieved during the send process seems like a hassle. I’m going to think about it more, for now, I may just have the user click the link in the email (which would generate the pdf from the template) thus avoiding any storage requirements. I also considered making a dummy attachment and just changing the contents and re-saving for each email but that doesn’t solve the latency issue.
      Last edited by czcpf; 07-20-2023, 06:10 PM.

      Comment


      • rabii
        rabii commented
        Editing a comment
        i understand your point, as far as i know no espocrm doesn't delete the files from the storage. perhaps you can create/extend the cleanup job and add a class that delete these files from storage.

      • czcpf
        czcpf commented
        Editing a comment
        That’s a good suggestion. I haven’t learned about the “cleanup job”. Is that per cron job or a global cleanup somewhere ?

      • rabii
        rabii commented
        Editing a comment
        it is a cron job that cleanup the system, here is some configuration to customise it https://docs.espocrm.com/administrat...rams/#clean-up

        here is the cleanup class https://github.com/espocrm/espocrm/b...leanup.php#L64
    • czcpf
      Senior Member
      • Aug 2022
      • 160

      #4
      I decided to take the following approach. Below is a complete example for others. You will need to replace things in {} per your requirements.

      What this does:
      1. Creates a System email.
      2. Creates an attachment of type pdf on the local file system.
      3. Sets the contents of the attachment using an existing pdf template.
      4. Attaches pdf to email using an existing pdf template.
      5. Deletes the attachment and the file from the local file system.

      PHP Code:
      <?php
      namespace Espo\Custom\Business\{CustomEntityName};
      
      use Espo\Custom\Entities\{CustomEntityName};
      use Espo\Entities\Attachment;
      use Espo\Entities\Email;
      use Espo\ORM\Entity;
      use Espo\Core\ORM\Entity as CoreEntity;
      
      use Espo\Core\Utils\Util;
      
      use Espo\Tools\Pdf\Service as PdfService;
      use Espo\Tools\Pdf\Params;
      
      use Espo\Core\{Exceptions\Error,
      InjectableFactory,
      Mail\Exceptions\SendingError,
      ORM\EntityManager,
      Utils\Log,
      Utils\TemplateFileManager,
      Mail\EmailSender,
      Utils\Config,
      Htmlizer\HtmlizerFactory as HtmlizerFactory,
      Utils\Language,
      Utils\ThemeManager,
      Utils\File\Manager as FileManager};
      
      class ReportSummaryEmail
      {
      /**
      * @var EntityManager
      */
      protected $entityManager;
      
      /**
      * @var EmailSender
      */
      protected $emailSender;
      
      /**
      * @var Config
      */
      protected $config;
      
      /**
      * @var TemplateFileManager
      */
      protected $templateFileManager;
      
      /**
      * @var Language
      */
      protected $language;
      
      /**
      * @var HtmlizerFactory
      */
      protected $htmlizerFactory;
      
      /**
      * @var Log
      */
      protected $log;
      
      /**
      * @var ThemeManager
      */
      protected $themeManager;
      
      /**
      * @var FileManager
      */
      protected $fileManager;
      
      /**
      * @var PdfService
      */
      protected $pdfService;
      
      
      
      public function __construct(
      private InjectableFactory $injectableFactory,
      EntityManager $entityManager,
      TemplateFileManager $templateFileManager,
      EmailSender $emailSender,
      Config $config,
      HtmlizerFactory $htmlizerFactory,
      Language $language,
      Log $log,
      ThemeManager $themeManager,
      FileManager $fileManager,
      PdfService $pdfService
      ) {
      $this->entityManager = $entityManager;
      $this->templateFileManager = $templateFileManager;
      $this->emailSender = $emailSender;
      $this->config = $config;
      $this->language = $language;
      $this->htmlizerFactory = $htmlizerFactory;
      $this->log = $log;
      $this->themeManager = $themeManager;
      $this->fileManager = $fileManager;
      $this->pdfService = $pdfService;
      }
      
      /**
      * @param {CustomEntityName} $entity
      * @throws SendingError
      * @throws Error
      */
      public function send(Entity $entity): void
      {/**
      * @var Email $email
      */
      $email = $this->entityManager->getNewEntity('Email');
      
      $email->set('to', {toEmail});
      
      $subjectTpl = $this->templateFileManager
      ->getTemplate({customType}, 'subject', $entity->getEntityType(), 'Custom');
      
      $bodyTpl = $this->templateFileManager
      ->getTemplate({customType}, 'body', $entity->getEntityType(), 'Custom');
      
      $subjectTpl = str_replace(["\n", "\r"], '', $subjectTpl);
      
      $additionalData = [];​
      
      $pdfTemplateId = {pdfTemplateId};
      
      $htmlizer = $this->htmlizerFactory->create();
      
      $subject = $htmlizer->render(
      $entity,
      $subjectTpl,
      '',
      $additionalData,
      true, //skip links
      true //skip inline attachment handling
      );
      
      $body = $htmlizer->render(
      $complianceReport,
      $bodyTpl,
      '',
      $additionalData,
      false, //skip links
      true //skip inline attachment handling
      );​
      
      $email->set('subject', $subject);
      $email->set('body', $body);
      $email->set('isHtml', true);//get contents from pdf template service
      $pdfContents = $this->pdfService->generate($entity::ENTITY_TYPE, $entity->getId(),$pdfTemplateId);/**
      * @var \Espo\Repositories\Attachment $attachmentRepository
      */
      $attachmentRepository = $this->entityManager
      ->getRDBRepository(Attachment::ENTITY_TYPE);
      
      /**
      * @var Attachment $attachment
      */
      $attachment = $attachmentRepository->getNew();
      
      $attachment->set([
      'name' => $entity->get('name') . '_' . $entity->getId() . '.pdf', // name your attachment
      'type' => 'application/pdf',
      'storage' => 'EspoUploadDir', //ensure it uses local storage
      'role' => Attachment::ROLE_ATTACHMENT,
      'contents' => $pdfContents->getString(),
      'size' => $pdfContents->getLength(),
      'parentType' => Email::ENTITY_TYPE,
      'field' => 'attachments'
      ]);
      
      $attachmentRepository->save($attachment); //save the new attachment
      $email->setAttachmentIdList([$attachment->getId()]); //add attachment id to email attachment list
      
      $this->emailSender
      ->withAttachments([$attachment])
      ->send($email); // send email with attachment
      
      $lfp = $attachmentRepository->getFilePath($attachment); // get attachment file path
      
      $attachmentRepository->remove($attachment); // remove attachment
      $this->fileManager->removeFile($lfp); //remove the actual local file
      }




      Comment


      • rabii
        rabii commented
        Editing a comment
        Glad you sorted it out
        I found out that there a hook for Attachment afterRemove but it only removes thumbs (images) from the file system.
    Working...