Help with sending attachments API

Collapse
X
 
  • Time
  • Show
Clear All
new posts

  • jacao
    replied
    Thanks. I've corrected code above.

    Leave a comment:


  • yuri
    commented on 's reply
    Note: 'fileContent' class should be named FileContent, according naming conventions in PHP

  • jacao
    replied
    Thanks a lot! Below code that works for me. It returns file content coded to Base64. Hope it will be usefull for other.

    .../espo/custom/Espo/Custom/FormulaFunctions/FileContent.php

    PHP Code:
    <?php
    namespace Espo\Custom\FormulaFunctions;

    use 
    Espo\Core\Formula\Exceptions\TooFewArguments;
    use 
    Espo\Core\Formula\Func;
    use 
    Espo\Core\Formula\EvaluatedArgumentList;
    use 
    Espo\Core\FileStorage\Manager;
    use 
    Espo\ORM\EntityManager;
    use 
    Espo\Entities\Attachment;

    class 
    FileContent implements Func
    {
    public function 
    __construct(
    private 
    Manager $fileStorageManager,
    private 
    EntityManager $entityManager,
    ) {}

    public function 
    process(EvaluatedArgumentList $arguments): string
    {
    if (
    count($arguments) < 1) {
    throw 
    TooFewArguments::create(1);
    }

    $id $arguments[0];
    $attachment $this->entityManager->getRDBRepositoryByClass(Attachment::class)->getById($id);

    if (!
    $attachment) {
    throw new 
    \RuntimeException("No attachment $id.");
    }

    $content $this->fileStorageManager->getContents($attachment);

    return 
    base64_encode($content);
    }
    }

    .../espo/custom/Espo/Custom/Resources/metadata/app/formula.json

    PHP Code:
    {
    "functionClassNameMap": {
    "fileContent""Espo\\Custom\\FormulaFunctions\\FileContent"
    },
    "functionList": [
    "__APPEND__",
    {
    "name""fileContent",
    "insertText""fileContent(ID)"
    }
    ]
    }
    ​ 
    Last edited by jacao; 10-04-2024, 08:30 AM.

    Leave a comment:


  • yuri
    replied
    You need something like this. Not tested.

    Code:
    <?php
    namespace Espo\Custom\FormulaFunctions;
    
    use Espo\Core\Formula\Exceptions\TooFewArguments;
    use Espo\Core\Formula\Func;
    use Espo\Core\Formula\EvaluatedArgumentList;
    use Espo\Core\FileStorage\Manager;
    use Espo\ORM\EntityManager;
    use Espo\Entities\Attachment;
    
    class AttachmentContents implements Func
    {
        public function __construct(
            private Manager $fileStorageManager,
            private EntityManager $entityManager,
        ) {}
    
        public function process(EvaluatedArgumentList $arguments): string
        {
            if (count($arguments) < 1) {
                throw TooFewArguments::create(1);
            }
    
            $id = $arguments[0];
    
            $attachment = $this->entityManager->getRDBRepositoryByClass(Attachment::class)->getById($id);
    
            if (!$attachment) {
                 throw new \RuntimeException("No attachment $id.");
            }
    
            return $this->fileStorageManager->getContents($attachment);
        }
    }​
    Last edited by yuri; 10-03-2024, 10:20 AM.

    Leave a comment:


  • yuri
    replied
    It might be a custom function. You can add custom functions. https://docs.espocrm.com/development...on-in-formula/

    Leave a comment:


  • jacao
    replied
    This thread is exactly what I've been looking for. However, I have a question - how did you manage to get the ext\file\contents() function shown in the screenshot from the first post? I can't seem to find it in my environment (Espo 8.4.1, Advanced Pack 3.4.6).​

    Leave a comment:


  • BigBoss
    replied
    Thank you very much, yuri . I've been looking for a solution for 3 months, you saved my life.




    Leave a comment:


  • yuri
    replied
    How your sub process looks like? Can you expand it and provide a screenshot. You need to add a Task with Send HTTP Request there. And use the same formula you used before but with $inputItem variable instead of the attachment ID.

    Leave a comment:


  • BigBoss
    replied
    "I now have the ID of each attachment. How can I obtain the 'name', 'type', and 'file' of each one?"




    Click image for larger version

Name:	image.png
Views:	321
Size:	35.0 KB
ID:	107137


    Click image for larger version

Name:	image.png
Views:	233
Size:	21.8 KB
ID:	107138


    Click image for larger version

Name:	image.png
Views:	239
Size:	22.6 KB
ID:	107139
    Attached Files

    Leave a comment:


  • yuri
    replied
    You can use multi-instance Sub-Process. If you have an array of attachments (or ids), pass them to each instance of the Sub-Process. That Sub Process will have Task that sends one attachment. It maybe bit tricky to figure out how to use it. But it's feasible.

    Leave a comment:


  • BigBoss
    replied
    Thank you, Davidjuan, but I want to use BPM. I want to extract the attachments from the email and send each attachment to my API individually, as I want to receive a single response for each attachment. With the method yuri explained to me, it works, but it retrieves all the attachments at once instead of each attachment separately.

    For example, if I have an email with 4 attachments, I want to extract all 4 and send each one individually to the API with the following format:

    ```json
    {
    "name": "{$$name}",
    "type": "{$$type}",
    "file": "{$$content}"
    }
    ```

    This way, I will receive a separate response for each attachment.​

    Leave a comment:


  • Davidjuan
    replied
    Hello,

    I'd be happy to help with that. Here’s a general approach you can follow to retrieve email attachments and send them to an API:

    1. Retrieve the Email Attachments:
    - Use an email client library (e.g., `imaplib` for IMAP or `smtplib` for SMTP in Python) to connect to your email server.
    - Authenticate and search for the email containing the attachments.
    - Retrieve and download the attachments to your local system.

    2. Send Attachments to the API:
    - Use a library like `requests` in Python to send HTTP requests.
    - Open each attachment file and send it to the API endpoint.

    Here is an example in Python:

    ```python
    import imaplib
    import email
    import requests

    # Connect to the email server and log in
    mail = imaplib.IMAP4_SSL('imap.your-email.com')
    mail.login('your-email@example.com', 'your-password')

    # Select the mailbox and search for the email
    mail.select('inbox')
    status, messages = mail.search(None, 'ALL')
    email_ids = messages[0].split()

    # Fetch the email by ID
    status, msg_data = mail.fetch(email_ids[-1], '(RFC822)')
    msg = email.message_from_bytes(msg_data[0][1])

    # Loop through the email parts to find attachments
    for part in msg.walk():
    if part.get_content_maintype() == 'multipart':
    continue
    if part.get('Content-Disposition') is None:
    continue

    filename = part.get_filename()
    if filename:
    # Save the attachment
    with open(filename, 'wb') as f:
    f.write(part.get_payload(decode=True))

    # Send the attachment to the API
    with open(filename, 'rb') as f:
    response = requests.post('https://your-api-endpoint.com/upload', files={'file': f})
    print(f'Uploaded {filename}, Response: {response.status_code}')

    # Close the connection to the mail server
    mail.logout()
    ```

    Replace the placeholders (`imap.your-email.com`, `your-email@example.com`, `your-password`, `https://your-api-endpoint.com/upload`) with your actual email server details, credentials, and API endpoint.

    This script:
    1. Connects to your email server and logs in.
    2. Searches for emails and retrieves the latest one.
    3. Extracts attachments and saves them locally.
    4. Sends each attachment to the specified API endpoint.

    Make sure you have the necessary libraries installed (`imaplib`, `email`, `requests`). You can install `requests` using `pip install requests`.

    I hope this helps! Let me know if you need further assistance.​

    Leave a comment:


  • BigBoss
    replied
    yes, but this sends all the attachments at once, I want to extract them and send one by one

    Leave a comment:


  • yuri
    replied
    You already have the $file variable which is an object. Use it by specifying 'file' in 'Payload from variable'. Erase the Payload textbox

    Leave a comment:


  • BigBoss
    replied
    Exemple !?

    Leave a comment:

Working...