Jump to content

Fetch Emails (SMTP) -> Save details to DB


dontknowphp

Recommended Posts

Hi,

I was wondering if there is any simple library that could read/fetch emails from an smtp email account that I could use to save the details on my database.

 

Use Case: Execute a cron job every X minutes to check if any new emails have arrived in the inbox and save them to the database (just like most of the support ticketing systems work)

Looking to create a simple support ticketing system.

Link to comment
Share on other sites

can you share an example of an imap connection? i've tried a few example ive found online but i cant make it to work.

<?php
	$db->query("SELECT * FROM st_settings");
	while($db->movenext())
	{
		$st_settings[$db->col["name"]] = $db->col["value"];
	}

	$inbox = imap_open("{".$st_settings["SMTP_HOST"].":".$st_settings["SMTP_PORT"]."/pop3/novalidate-cert}", $st_settings["SMTP_USERNAME"], $st_settings["SMTP_PASSWORD"]);
	$num = imap_num_msg($inbox);
	echo $num;
	
// close the connection
imap_expunge($inbox);
imap_close($inbox);

?>

 

Link to comment
Share on other sites

Sure.  

First, as mentioned before this is not SMTP, so all the SMTP_* constants you are using are either the wrong values or incorrectly named.  Either make new IMAP settings to use or rename your constants.

Second, this is based on some code I have that checks an email account for a one-time-password code so I can login and download data from a site.

<?php
//Example parameters.
$host = '{imap.example.com:993/ssl/readonly}';
$mailbox = 'otp@example.com';
$password = '';

function getSecurityCode(string $host, string $mailbox, string $password) : ?string{
    $authCode = null;
    $startTime = time();
    do {
        sleep(5);
        $handle = imap_open($host, $mailbox, $password, OP_READONLY, 5);
        if (!$handle){
            throw new RuntimeException('Unable to open mailbox');
        }

        $messageList = imap_sort($handle, SORTDATE, 1);
        foreach ($messageList as $messageNumber){
            $messageInfo = imap_fetch_overview($handle, $messageNumber)[0];
            if (isOTPEmail($messageInfo) && isReceivedInLast5Minutes($messageInfo)){
                $authCode = extractAuthCode(imap_body($handle, $messageNumber));
                break;
            }
        }

        imap_close($handle);
    } while (!$authCode && time() - $startTime < 300);

    return $authCode;
}

function isOTPEmail(stdClass $messageInfo) : bool{
    if (!isset($messageInfo->subject)){
        return false;
    }

    return stripos($messageInfo->from, 'donotreply@example.com') !== false
        && stripos($messageInfo->subject, 'One-Time Passcode') !== false;
}

function isReceivedInLast5Minutes(stdClass $messageInfo) : bool{
    if (!isset($messageInfo->date)){
        return false;
    }

    $date = DateTime::createFromFormat(DateTimeInterface::RFC2822, $messageInfo->date);
    if ($date === false){
        $date = DateTime::createFromFormat(DateTimeInterface::RFC2822 . ' (\G\M\T)', $messageInfo->date);
    }

    if ($date === false){
        return false;
    }

    $now = new DateTime('', $date->getTimezone());
    $now->sub(new DateInterval('PT5M'));

    return $date > $now;
}

 

Edited by kicken
  • Great Answer 1
Link to comment
Share on other sites

Hello @gizmola @kicken

Thank you for your help, i ended up using the library from barbushin.

However, i have one more question.

How can I "detect" which reply is associated with the original email?

Steps

1) User sends email to example@example.com

2) cron job runs checks for new emails and creates new "tickets" (save to db)

3) Admin replies from the webapp

4) User replies to the admin's response

5) cron job runs detects new email -> i need somehow to map it with the existing ticket so the system won't create a new ticket again.

 

I suspect that the "messageid" has something to do with this but i haven't found any way to take advantage of it.

Link to comment
Share on other sites

In my experience, such systems usually just have some identifier in the email, usually the subject which is used to associate the email with the internal ticket system.

If you want to try and do it without such an identifier, look at the In-Reply-To and/or References headers which should contain the original email message id.

 

Link to comment
Share on other sites

17 hours ago, kicken said:

In my experience, such systems usually just have some identifier in the email, usually the subject which is used to associate the email with the internal ticket system.

 

The subject may change in the ticketing, so mapping it with the subject may not be reliable

 

17 hours ago, kicken said:

If you want to try and do it without such an identifier, look at the In-Reply-To and/or References headers which should contain the original email message id.

 

I am confused with this bit, when i am replying through the ticket system do i need to construct the "message id" or is that automatically done?

 

Link to comment
Share on other sites

2 hours ago, dontknowphp said:

The subject may change in the ticketing, so mapping it with the subject may not be reliable

You wouldn't match the whole subject, just some identifier.  For example the subject may be: [Ticket #1234] Help with something.  Then you'd just extract the 1234 and lookup that ticket.  Even if someone changes the subject, so long as that prefix is left in it will be fine.  In my experience, people do not typically change a subject when replying so it should be fairly reliable.  If for some reason you cannot automatically match it to a ticket, you could put the message into some queue for a person to manually assign to a ticket.

3 hours ago, dontknowphp said:

I am confused with this bit, when i am replying through the ticket system do i need to construct the "message id" or is that automatically done?

If you're generating the email then you'll probably need to generate the Message-Id header as well.  If you're using a library to create and send emails it might do that automatically.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.