barbushin / php-imap

Manage mailboxes, filter/get/delete emails in PHP (supports IMAP/POP3/NNTP)
MIT License
1.65k stars 459 forks source link

Save replies to existing ticket? #691

Open patriotaki opened 1 year ago

patriotaki commented 1 year ago

Environment (please complete the following information):

Your Text Hello,

How can I map a reply with an existing email? I am trying to create a basic support ticketing system, lets say for example an email is sent to test@example.com, when the cron job executes a new ticket is being created in my web app and I reply through my system. If the user replies back through his email client, how can I detect it and add it as a reply and not as a new ticket?

Sebbo94BY commented 1 year ago

Hello @patriotaki, I had the same use-case and question a few years ago. 😅

Each email has an unique Message-ID. Those must be referenced in all related emails of the same email thread/conversation. So your ticket system needs to store each single Message-ID to be able to reply to them in order to build the email thread/conversation.

I've shared my solution on Stackoverflow in the past. It also includes an example based on Laravel. You might want to check it out: https://stackoverflow.com/a/50768215/2966991

patriotaki commented 1 year ago

Hello @Sebi94nbg thank you for the reply. From what I see the messageId is only present in replies? and not in the first email that is being sent?

Sebbo94BY commented 1 year ago

@patriotaki Usually, every email has a Message-ID.

However, RFC 2822 3.6.4 Identification fields specifies, that every email (message) SHOULD have it:

Though optional, every message SHOULD have a "Message-ID:" field.

So if an email has a Message-ID or not, depends on the software, which sent the email.

I personally don't know any case, where this header is not set / available. In my cases it was always available / set.

In worst case, your ticket system should be able to handle incoming emails without this header field.

patriotaki commented 1 year ago

@Sebi94nbg hmm thats weird, emails that are sent from gmail do not have a message ID in my tests

I am trying to find the correct logic of how ticket system should work. I guess that everytime that a ticket is created (either by form or by email) a unique message id must be generated by the software (me) that should be included in the reply-email (when a staff/admin replies). This way when the user replies through the email client ill be able to "detect" that its a reply to that specific email.

So in conclusion all emails that are sent by the software (me) should have a unique message id generated by the software (me), even if the initial sender does not have a message id?

Is my understanding correct?

Sebbo94BY commented 1 year ago

Are you sure? I've just sent an email from a Gmail business account to myself and it had a Message-ID. The private Gmail stuff usually behaves identical. I've found an old email from a private Gmail account and I also could find it there.

As written: The Message-IDs are the way to go. That's a RFC standard and usually also used by email clients for building the email threads/conversations. Also Gmail uses those therefore.

Yes, your ticket system needs to set for each sending email the header field Message-ID with an unique value.

Additional, if its a reply to an existing email thread/conversation, you also need to set ALL Message-IDs of the previous emails in the References header field.

Just as my $this->withSwiftMessage(function ($swiftmessage) { ... } on Stackoverflow shows it: https://stackoverflow.com/a/50768215/2966991 :)

patriotaki commented 1 year ago

@Sebi94nbg Yes, i've tried multiple times, message id is always empty, unless i am not using the correct code. This is the output Image: https://monosnap.com/file/yHXbdxfEZUn8OwyvMh3FJ8C9moBArz

code: echo 'from-name: '.(string) ($email->fromName ?? $email->fromAddress)."\n"; echo 'from-email: '.(string) $email->fromAddress."\n"; echo 'to: '.(string) $email->toString."\n"; echo 'subject: '.(string) $email->subject."\n"; echo 'message_id: '.(string) $email->messageId."\n";

Sebbo94BY commented 1 year ago

Ah, using this library, ok. But in a mail client, you should see it.

Can you find it in $email->headersRaw? If yes: Can you please provide your censored headers, so that I can debug and fix it, if necessary?

patriotaki commented 1 year ago

@Sebi94nbg Message id is still empty in headersRaw

h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; followed by a long string, unless the values are encoded in that long string?

Sebbo94BY commented 1 year ago

headersRaw should return you a huge text block with all available headers. It should simply contain the headers in the raw format. Unchanged from this library.

See

If you don't even get this, then you probably have a different problem. How does your code look like?

Did you also check the email headers in Gmail? There you should see a Message-ID. Click on "Show original" at the three dots on the right side within an open email.

patriotaki commented 1 year ago

The message id is visible in the gmail when clicking show original code sample below:

`

            $user = $department_value["email"];
    $host = $department_value["imap_host"];
    $port = $department_value["imap_port"];
    $pass = $department_value["imap_password"];
    $auth = $department_value["imap_secure"];

    if($user!="" && $host!="" && $pass!="" && $port!="" && $auth!="")
    {
        $host_splitted = explode($host, ".");
        $host_s = "";
        if(count($host_splitted)>2){
            $host_s = "{".$host;
        }
        else
        {
            $host_s = "{mail.".$host;
        }

        $auth_s = "";
        if($auth=="ssl")
        {
            $auth_s = "/ssl/novalidate-cert";
        }
        else
        {
            $auth_s = "";
        }

        $mailbox = new PhpImap\Mailbox(
            $host_s.':'.$port.$auth_s.'}INBOX', // IMAP server and mailbox folder
            $user, // Username for the before configured mailbox
            $pass, // Password for the before configured username
        );

        try {
    $mail_ids = $mailbox->searchMailbox('ALL');
    } catch (ConnectionException $ex) {
        echo $ex->getErrors('first');
        continue;

    } catch (Exception $ex) {
        echo $ex->getMessage();
        continue;

    }

        foreach ($mail_ids as $mail_id)
        {
    echo "+------ P A R S I N G ------+<br>";

    $email = $mailbox->getMail(
        $mail_id, // ID of the email, you want to get
        false // Do NOT mark emails as seen (optional)
    );
    echo 'from-name: '.(string) ($email->fromName ?? $email->fromAddress)."<br>";
    echo 'from-email: '.(string) $email->fromAddress."<br>";
    echo 'to: '.(string) $email->toString."<br>";
    echo 'subject: '.(string) $email->subject."<br>";
    echo 'message_id: '.(string) $email->messageId."<br>";`
Sebbo94BY commented 1 year ago

Mhmm, looks good in general. I can't see anything, what could cause the issue. But I also can't see your full code, so the issue might be somewhere else. You're using continue within the try-catch block, but this will only work in loops, which I can't see there.

Also checking the variables, if they are empty or not is not really necessary - the connection attempt would throw either a connection exception or authentication failure, which can be catched. If you really want to check them, you may also rather want to use something like !empty(trim($user)) to be sure, that it's empty or not.

When you add a echo 'headers_raw: '.(string) $email->headersRaw."<br>"; under your PARSING code, you should see the respective headers as they are fetched by the PHP IMAP function(s). If the Message-ID is already missing there, then this is probably an issue of your specific used PHP version or your code.

Please also ensure, that you're using the latest version https://github.com/barbushin/php-imap/releases/tag/5.0.1 of this library and try it again. This also works with PHP 7.4, which you use.

patriotaki commented 1 year ago

@Sebi94nbg Yes, the process is in a loop thus the keyword continue

this is the a partial result of headersRaw() , as far as I can see there is no message-id, I've tried other email clients but again no message-id. I haven't included the whole header because no where else the word message-id was present. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=B4CVInUWzAN/Ra9i2OOtLCnYKxsQpMggMCNQN6FAjAs=; b=A3K7rCwbDUUBYWzlVgDf8cxLVZ3opsJcsrJp5uXMeTd+Px+vAFfXO4IdQ+fS2yrVK Idddt/B3sYZI6qL6MBIWFCA2mwlqDXb0sc9cveEANwfwAFMPkQzBqxqNw3fOTKC0Plc5 XCG0aONdp6Dbr9gDde0imyhhzbNxXPd4u0uckA9Ci1h7nPRic+Zr6gyEpqAwKmE1APg cgulkDaC0aw9XZdpnUfRbEXVNw55C4D1TRwYLzSRFbaxm0OngFlPlxjPXsp5arITD8Vm r4aSYcDBKyrrJTnQvJg1viWH+nI5QDg4mMtBX4zhJvXRXp0pAfODrLZMxolVq+5JS/D NP/Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=B4CVInUWzAN/Ra9i2OOtLCnYKxsQpMggMCNQN6FAjAs=; b=HhSa+ouevUgP3ub/nkX/dg0s3HlKwh9dRTOPfVOt6O7cFwJI5KVke9prz8QxkoKIa kT0J73hAssvsOKIdKE+C0lBJdhQmD4fo+6KXmGz5hl2teK6q8/PGEeI0KMj4NxSlLVot W99jnBsFPQ/lwonzTpklrduQDic5BOeaNXyc+SlF5QGXAmk2PHXXFNy+E5lKK7GR0g uOK3EY4+3tVLRBOgszmGsnZz2TfaeQ+hGwfgngGLjqTJwcdI7GshPtplx9JnTL1LtiVh cFIE6YadsQkYFKwQK9qhvmF61zBzsJ6AkqFcTXc31IKciEfVUStYkvrV1ucalVPLQlj tcvg==

patriotaki commented 1 year ago

@Sebi94nbg PS: I tried Outlook email, and still no message ID

patriotaki commented 1 year ago

@Sebi94nbg sorry for bumping, just want to know if this is a "global" issue or is isolated to my code only? I haven't figured it out yet, messageID is always empty

Sebbo94BY commented 1 year ago

I‘ve also asked this myself. I need to test it. But due to christmas and my main work, I had no time to test it yet. Am 15.12.2022 um 09:43 schrieb patriotaki @.***>: @Sebi94nbg sorry for bumping, just want to know if this is a "global" issue or is isolated to my code only? I haven't figured it out yet, messageID is always empty

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you were mentioned.Message ID: @.***>

patriotaki commented 1 year ago

Great, let me know once you have more information. Enjoy your holidays.

I‘ve also asked this myself. I need to test it. But due to christmas and my main work, I had no time to test it yet.

patriotaki commented 1 year ago

Hi @Sebi94nbg ,

Happy new year!

from what I can see I am not the only one with an empty message id in header response (see headers from issue #698) seems like a bug, is there any ETA of when this will be fixed? It's kinda urgent for me so if there are there any workarounds that I can do to get the message id please let me know.