Read gmail with Zend Framework - php

Im trying to read mails from a gmail apps account by using Zend Framework. I've just transfered the Zend Framework dir to my server (path: /Zend/library/).
How do I load the Zend Framework and the Mail module? And how do I further read the mail?
I've tried the following with no results:
$path = 'Zend/library/';
set_include_path(get_include_path() . PATH_SEPARATOR . $path);
I believe the syntax for reading the inbox is something like:
$mail = new Zend_Mail_Storage_Imap(array('host' => 'imap.gmail.com', 'user' => "name#domain.com", 'password' => "mypassword", 'ssl' => 'SSL'));
EDIT
The following code works:
$path = 'Zend/library/';
set_include_path(get_include_path() . PATH_SEPARATOR . $path);
require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();
$mail = new Zend_Mail_Storage_Imap(array('host' => 'imap.gmail.com',
'user' => 'mail#domain.com',
'password' => 'password',
'ssl' => 'SSL'));
echo $mail->countMessages();`
... but when i try to echo unread emails:
echo "Unread mails:\n";
foreach ($mail as $message) {
if ($message->hasFlag(Zend_Mail_Storage::FLAG_SEEN)) {
continue;
}
// mark recent/new mails
if ($message->hasFlag(Zend_Mail_Storage::FLAG_RECENT)) {
echo '! ';
} else {
echo ' ';
}
echo $message->subject . "\n";
}
I get the following message:
Fatal error: Uncaught exception 'Zend_Mail_Storage_Exception' with message 'cannot login, user or password wrong' in /var/www/zvinx.dk/test/Zend/library/Zend/Mail/Storage/Imap.php:279 Stack trace: #0 /var/www/zvinx.dk/test/gmail.php(11): Zend_Mail_Storage_Imap->__construct(Array) #1 {main} thrown in /var/www/zvinx.dk/test/Zend/library/Zend/Mail/Storage/Imap.php on line 279
It says the username or password is wrong, which is weird cause I didnt change it from when it was working... How come this error occur?

the gmail settings are a little tricky. try:
$mail = new Zend_Mail_Storage_Imap(array('host' => 'imap.gmail.com',
'user' => 'mail#domain.com',
'port' => '993',
'password' => 'password',
'ssl' => 'tls',
'auth' => 'login'
));
NOTE: the gmail are using the SSL/TLS protocol which apparently is different than the standard SSL.

You really don't think that you can start using Zend Framework without reading/learning about the basics of the framework? At least take a look at the quickstart on how to use the framework with the autoloading features and then dive into the Zend_Mail documentation, more specifically the part that says "Reading Mail Messages"

There are the login setting i use to read emails via IMAP and dump attached files
public function imapAction()
{
$config = array('host'=> 'imap.gmail.com',
'user' => 'xx',
'password' => 'xx',
'ssl' => 'SSL',
'port' => 993);//995 pop, imap 993
$mail = new Zend_Mail_Storage_Imap($config);
$maxMessage = $mail->countMessages();
$this->logger->info($maxMessage);
for ($i = $maxMessage; $i <= $maxMessage; $i++)
{
$message = $mail->getMessage($i);
$this->logger->info($i.'Mail from '.$message->from.':'.$message->subject);
if($message->isMultipart())
{
$this->logger->info("has attachments");
$part = $message->getPart(2);
$cnt_typ = explode(";" , $part->contentType);
$name = explode("=",$cnt_typ[1]);
$filename = $name[1];//It is the file name of the attachement in browser
//This for avoiding " from the file name when sent from yahoomail
$filename = str_replace('"'," ",$filename);
$this->logger->info($filename);
$attachment = base64_decode($part->getContent());
$fhandle = fopen($filename, 'w');
fwrite($fhandle, $attachment);
fclose($fhandle);
}
}
}

I had the same issue and this instruction has helped me.
Quit all mail clients that are accessing the affected Gmail account. This means the Mail app on the iPhone and any other place you are accessing your Gmail from such as a computer.
Open browser and navigate to this page: http://www.google.com/accounts/DisplayUnlockCaptcha
Enter your full Gmail address, password and type the characters you see in the picture. Touch the unlock button to verify your account.
Try to read mails from a gmail apps account by using Zend Framework. Your Gmail access should be restored.

If you encounter this error and you are 100% sure about the password you provided it might come from the 2 factor authentication you set on your google account.
Google help gives indications on what to do in this case. I manage to get access to my account by generating an AppPassword in my case

Related

PHP - Connect mailbox office 365 with OAuth

Please forgive my amateurism both in php and on stackoverflow.
I have a PHP script that reads emails from an office 365 mailbox, for this I use a standard connection:
$Inbox = imap_open('{Outlook.office365.com:993/imap/ssl}', 'mabal#mydomain.com', 'mypassword');
Then to read the new emails received, I used the command:
$UnRead = imap_search($Inbox, 'UNSEEN');
Starting 20221001 - October 1, 2022, Microsoft will remove this authentication and require OAuth2 authentication.
I registered my web application at Microsoft Azure and tried several settings. I have done a lot of research that allows me to connect to the mailbox to be able to read the mails without going through an interaction with a user. I've found nothing.
Does anyone have a step-by-step solution to retrieve a variable bound to an "imap_open" or do you have to use a completely different system.
Thanks for your help.
It's been a wild ride for me and my coworkers but we found a solution.
1 - Configure your mail box in Azure
(I didn't do this part so i can't help you more than that ! )
Edit : Thanks to parampal-pooni, this link explains how to configurate in azure.
You will need :
The client Id
The tenant Id
The secret client
The redirect Uri (Set it to http://localhost/test_imap)
2 - Grab a code to get a token
Construct this url :
$TENANT="5-48...";
$CLIENT_ID="c-9c-....";
$SCOPE="https://outlook.office365.com/IMAP.AccessAsUser.All";
$REDIRECT_URI="http://localhost/test_imap";
$authUri = 'https://login.microsoftonline.com/' . $TENANT
. '/oauth2/v2.0/authorize?client_id=' . $CLIENT_ID
. '&scope=' . $SCOPE
. '&redirect_uri=' . urlencode($REDIRECT_URI)
. '&response_type=code'
. '&approval_prompt=auto';
echo($authUri);
Go to the link, connect to the mail box with the passeword.
Once it done, you will be redirect to : http://localhost/test_imap?code=LmpxSnTw...&session_state=b5d713....
Save the code (remove the '&' at the end !) and the session state inside the url.
These codes expired after a few hours !
3 - Get an access token
$CLIENT_ID="c-9c-....";
$CLIENT_SECRET="Y~tN...";
$TENANT="5-48...";
$SCOPE="https://outlook.office365.com/IMAP.AccessAsUser.All offline_access";
$CODE="LmpxSnTw...";
$SESSION="b5d713...";
$REDIRECT_URI="http://localhost/test_imap";
echo "Trying to authenticate the session..";
$url= "https://login.microsoftonline.com/$TENANT/oauth2/v2.0/token";
$param_post_curl = [
'client_id'=>$CLIENT_ID,
'scope'=>$SCOPE,
'code'=>$CODE,
'session_state'=>$SESSION,
'client_secret'=>$CLIENT_SECRET,
'redirect_uri'=>$REDIRECT_URI,
'grant_type'=>'authorization_code' ];
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_POSTFIELDS, http_build_query($param_post_curl));
curl_setopt($ch,CURLOPT_POST, 1);
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
$oResult=curl_exec($ch);
echo "result : \n";
var_dump($oResult);
The access_token given in response is going to work only for a few hours. ( If your script is going to be launch on a daily basic you need to recreate a token. I'm going to show you how in the part 5 ! Save the refresh_token inside $oResult. If you don't have the "refresh_token" you have forgot to put "offline_access" in the scope)
Edit : I forgot to add the redirect_uri in this step, thank jose ayram
4 - Connect to the mail box
Now choose your favorite library ;) ! We will use webklex/php-imap for this example (https://github.com/Webklex/php-imap)
include __DIR__.'/vendor/autoload.php';
use Webklex\PHPIMAP\ClientManager;
$access_token="EH.j8s5z8...";
//$cm = new ClientManager($options = ["options" => ["debug" => true]]);
$cm = new ClientManager();
$client = $cm->make([
'host' => 'outlook.office365.com',
'port' => 993,
'encryption' => 'ssl',
'validate_cert' => false,
'username' => 'mymailbox#domain.com',
'password' => $access_token,
'protocol' => 'imap',
'authentication' => "oauth"
]);
try {
//Connect to the IMAP Server
$client->connect();
$folder = $client->getFolder('INBOX');
$all_messages = $folder->query()->all()->get();
//DONE ! :D
} catch (Exception $e) {
echo 'Exception : ', $e->getMessage(), "\n";
}
5 - Connecting to the mail box everyday
include __DIR__.'/vendor/autoload.php';
use Webklex\PHPIMAP\ClientManager;
$CLIENT_ID="c-9c-....";
$CLIENT_SECRET="Y~tN...";
$TENANT="5-48...";
$REFRESH_TOKEN="EebH9H8S7...";
$url= "https://login.microsoftonline.com/$TENANT/oauth2/v2.0/token";
$param_post_curl = [
'client_id'=>$CLIENT_ID,
'client_secret'=>$CLIENT_SECRET,
'refresh_token'=>$REFRESH_TOKEN,
'grant_type'=>'refresh_token' ];
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_POSTFIELDS, http_build_query($param_post_curl));
curl_setopt($ch,CURLOPT_POST, 1);
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
//ONLY USE CURLOPT_SSL_VERIFYPEER AT FALSE IF YOU ARE IN LOCALHOST !!!
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER, false);// NOT IN LOCALHOST ? ERASE IT !
$oResult=curl_exec($ch);
echo("Trying to get the token.... \n");
if(!empty($oResult)){
echo("Connecting to the mail box... \n");
//The token is a JSON object
$array_php_resul = json_decode($oResult,true);
if( isset($array_php_resul["access_token"]) ){
$access_token = $array_php_resul["access_token"];
//$cm = new ClientManager($options = ["options" => ["debug" => true]]);
$cm = new ClientManager();
$client = $cm->make([
'host' => 'outlook.office365.com',
'port' => 993,
'encryption' => 'ssl',
'validate_cert' => false,
'username' => 'mymailbox#domain.com',
'password' => $access_token,
'protocol' => 'imap',
'authentication' => "oauth"
]);
try {
//Connect to the IMAP Server
$client->connect();
}catch (Exception $e) {
echo 'Exception : ', $e->getMessage(), "\n";
}
}else{
echo('Error : '.$array_php_resul["error_description"]);
}
}
I hope it will help you.
Execute this curl
Replace client_id, client_secret and tenant_id
In scope you can try to use https://outlook.office365.com/.default, https://graph.microsoft.com/.default or https://outlook.office.com/.default
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'client_id={CLIENT_ID}&scope=https%3A%2F%2Foutlook.office365.com%2F.default&client_secret={CLIENT_SECRET}&grant_type=client_credentials' 'https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token'
PHP-imap login
<?php
// ....
$instance = new ClientManager();
$this->client = $instance->make([
'host' => "outlook.office365.com",
'port' => "993",
'encryption' => 'ssl',
'validate_cert' => true,
'username' => "email#outlook.com",
'password' => $curlAcessToken, // Access token curl
'protocol' => 'imap',
'authentication' => "oauth",
]);

Send Mail to Multiple Address in Cakephp 3 : Cannot modify an existing config

I am trying to send email to multiple recipient address in cake php 3.
my codes are :
$this->loadModel('AsIndividualDetails');
$EmailDetails = $this-> AsIndividualDetails->find('all',['fields'=>'email']);
$EmailDetails = $EmailDetails->toArray();
foreach ($EmailDetails as $key => $a) {
$this->loadModel('DomainEmailDetails');
$DomainEmailDetails = $this-> DomainEmailDetails->find('all')->first();
$DomainEmailDetails = $DomainEmailDetails->toArray();
$host = 'ssl://'.$DomainEmailDetails['host_name'];
$username = $DomainEmailDetails['user_name'];
$password = $DomainEmailDetails['user_password'];
$port = $DomainEmailDetails['port'];
$email_to = $a['email'];
$senderName = 'abc';
$email_id ='xyz110#gmail.com';
Email::configTransport('WebMail', [
'className' => 'Smtp',
'host' => $host,
'port' => $port,
'timeout' => 30,
'username' => $username,
'password' => $password,
'client' => null,
'tls' => null,
]);
////////// SEND MAIL
$email = new Email('WebMail');
$email ->template('default','default')
->emailFormat('both')
->from([$username => $senderName])
->to($email_to)
->replyTo($email_id)
->subject('Client Message');
$response = $email->send('My msg');
if($response){
echo 'success';
}else{
echo 'failed';
}
}
When I run this script just only one mail send successfully and after that an error has come :
Cannot modify an existing config "WebMail"
How to solve this error and send mail to all recipient mail address.
If you really need set the config inside a loop, you could delete it before rewrite the config:
use Cake\Mailer\Email;
Email::dropTransport($key);
See Class Email API for more info
Make your email configuration outside of the loop. You don't want to try and establish the configuration every time you send the emails - just one time. Then send all the emails based on that one configuration.

How do I properly set up PHPMailer with Gmail SMTP Servers?

I have a form that basically has 3 radio buttons that will let you pick a staff member you want to get in contact with. The form requires a name, email and message. I cannot find where it tells me what the error is. I have debugging on but do not know where the error is coming from.
My goal is to have it so that the person they select will be emailed and when the email is sent it will be redirected to a page that has the correct staff members info on it. However for the life of me I cannot get this to work. I believe everything works correct but when I inserted the code that I found on SO to connect to the SMTP servers and email the contact form input my formProcess.php breaks.
EDIT: With the help of some of you here I have found the solution to 2 of the errors I am getting. However now that I have fixed these errors I am getting a different error. I am now receiving this:
2015-12-23 04:42:59 SMTP ERROR: Failed to connect to server: Cannot allocate memory (12) 2015-12-23 04:42:59 SMTP connect() failed. https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting 2015-12-23 04:42:59 SMTP ERROR: Failed to connect to server: Cannot allocate memory (12) 2015-12-23 04:42:59 SMTP connect() failed. https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting
Warning: Cannot modify header information - headers already sent by (output started at /www/contact/phpmailer/class.smtp.php:234) in /www/contact/formProcess.php on line 80
EDIT 2: I have uploaded it to my hosted server. It has solved the error mentioned above. I now have an issue with the password failing, even though I have signed in using the password I am using in the code. Instead of copy/pasting the error message you can see it live on my site for yourself.
EDIT 3: I just noticed that there is an email from Gmail that says "Someone tried to sign in to your Google Account from an app that doesn't meet standard security standards." This can't be a coincidence can it? Is this why I cannot connect? and if so what can I do to meet security standards?
EDIT 4: I have now got everything working fine except for 2 things. 1, for some reason it is sending the emails twice. I am not sure why but I feel like I can figure it out. The real issue I am having now is that I now want to include Googles reCAPTCHA to my form as well. Everything works fine until I added this bit of code that I thought would verify if the reCAPTCHA was successful and if it wasn't just add an error to my code, but after I entered the code below to do that my code breaks.
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => 'https://www.google.com/recaptcha/api/siteverify',
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => [
'secret'=>'Well it says secret for a reason!',
'response'=> $_POST['g-recaptcha-response']
]
]);
$response = json_decode(curl_exec($curl));
if (!$response->success){
$errors[] = 'There was a problem with reCAPTCHA, please try again.';
};
And bellow is all code that processes the form.
<?php
session_start();
ini_set('display_errors', 1); error_reporting(E_ALL);
require_once 'PHPMailerAutoload.php';
$errors = [];
$toWho ='';
if(isset($_POST['name'], $_POST['email'], $_POST['message'], $_POST['who'])){
$fields = [
'name' => $_POST['name'],
'email' => $_POST['email'],
'message' => $_POST['message'],
'who' => $_POST['who']
];
foreach($fields as $field => $data) {
if(empty($data)) {
$errors[] ='The ' .$field. ' field is required.';
}
}
if ($fields['who'] == "staff1") {
$toWho = 'staff1#domain.com';
} else if ($fields['who'] == "staff2") {
$toWho = 'staff2#domain.com';
} else {
$toWho = 'staff3#domain.com';
}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => 'https://www.google.com/recaptcha/api/siteverify',
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => [
'secret'=>'Well it says secret for a reason!',
'response'=> $_POST['g-recaptcha-response']
]
]);
$response = json_decode(curl_exec($curl));
if (!$response->success){
$errors[] = 'There was a problem with reCAPTCHA, please try again.';
};
if(empty($errors)) {
$mail = new PHPMailer;
$mail->isSMTP();
$mail->SMTPAuth = true;
$mail->smtpSecure = 'tls';
$mail->Port = 587;
// $mail->SMTPDebug = 3;
$mail->Host = 'mailen3.cloudsector.net';
$mail->From = "No-reply#domain.com";
$mail->Username = 'No-Reply#domain.com';
$mail->Password = 'PAsswoRD';
$mail->SetFrom("No-reply#domain.com", "No Reply" );
$mail->AddReplyTo($fields['email'], $fields['name']);
$mail->AddAddress($toWho, $fields['who']);
$mail->Subject = $fields['name'] . ' wants to talk!';
$mail->Body = 'From: ' .$fields['name']. ' (' .$fields['email']. ') ' .$fields['message']. ;
$mail->send();
if($mail->send()) {
header('Location: ../../' .$fields['who']. 'thanks.php');
die();
}else {
$errors[] = 'Sorry! Something went wrong and your message could not be sent. Please try again ';
}
}
} else {
$errors[] = 'Something went wrong.';
}
$_SESSION['errors'] = $errors;
$_SESSION['fields'] = $fields;
header('Location: index.php');
?>
Try displaying errors by adding the following code at the top of your script:
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
If you're getting a server error 500, Try commenting out small blocks of code until the script works. That way you can identify the problem.

Amazon SES + PHP

I'm trying to set up amazon SES with PHP. I've scoured the internet and the documentation for AWS PHP SDK but I only see outdated scripts on how to include the actual library and send e-mail. Does anyone here have a working script for using Amazon SES with PHP?
This is the closest I've found to test the script but it doesn't work:
require 'src/aws.phar';
use Aws\Common\Enum\Region;
use Aws\Ses\SesClient;
try {
$ses = SesClient::factory(array(
'key' => 'AKIAJ4ERVU6XXXXXXX',
'secret' => 'kMgagzJmB4Xjw7UD+Md0KNgW+CTE2jCXXXXX/',
'region' => Region::US_EAST_1
));
$ses->verifyEmailIdentity( array(
'EmailAddress' => 'jason#aol.com'
));
}
catch( Exception $e )
{
echo $e->getMessage();
}
First, you would want to disable/delete and generate new keypairs so that you would not have to face bad situation as there are scrapers/bots and people who might misuse your access key-pairs.
As for your original question, you didn't describe what didn't work for you. Anyway, since you wanted a working version, check the source code of this: https://github.com/daniel-zahariev/php-aws-ses which will give you enough idea to get yours working.
This is the working code that i got for you, let me know if this helps
<?php
require 'aws.phar';
use Aws\Ses\SesClient;
$client = SesClient::factory(array('region'=>'us-east-1','version'=>
'latest','credentials' => array('key' => 'xxxxx','secret' => 'xxxxxx',)));
$msg = array();
$msg['Source'] = $message['from'];
$msg['Destination']['ToAddresses'][] = $to_address;
$msg['ReplyToAddresses'][] = $from;
$msg['Message']['Subject']['Data'] = $subject;
$msg['Message']['Subject']['Charset'] = "UTF-8";
$msg['Message']['Body']['Html']['Data'] = $body;
$msg['Message']['Body']['Html']['Charset'] = "UTF-8";
try{
$result = $client->sendEmail($msg);
$logmsg = "Passed ".from." - ".to_address;
} catch (Exception $e) {
$logmsg = "Failed ".$message['from']." - ".$to_address;
error_log('Failed Email '.from." - ".$to_address);
}

Sending email via SMTP on zend framework

$config = array('auth' => 'login',
'username' => '****#gmail.com',
'password' => '****',
'port' => '25',
'ssl' => 'tls');
$transport = new Zend_Mail_Transport_Smtp('smtp.googlemail.com', $config);
what should i do after that, where can i put the body and the recipient address.
Its described in the manual of Zendframework
Zend_Mail::setDefaultTransport($transport);
Then somewhere else instanciate Zend_Mail, write your mail and send it.
See the documentation for full examples (although the Zend docs admittedly often aren't great).
Based on a comment here:
$mail = new Zend_Mail();
$tr = new Zend_Mail_Transport_Smtp(...);
$mail->setFrom('...', 'Server');
$mail->addTo($to, '....');
$mail->setSubject($subject);
$mail->send();
Zend_Mail::setDefaultTransport($tr);
$mail->setBodyText($body);
Your example shows an empty link so it wont display anything.
Unless this is a modified example you used to post on here?
Does the following display anything when you run it, if not what do you get.
$smtpHost = new Zend_Mail_Transport_Smtp('smtp.gmail.com', $config);
$mail = new Zend_Mail();
$mail->setBodyText($form->getValue('body'));
$mail->setBodyHtml('my link');
$mail->setFrom($certtime['email'], $certtime['first_name'] . $certtime['last_name']);
$mail->addTo($form->getValue('reciever'));
$mail->setSubject('My Certificate');
$mail->send($smtpHost);

Categories