Could you please tell me why I set returnPath using zend_mail received email has to return-path headers (I view them in gmail) using smtp trasport:
Return-Path: <bounce#domain.com> //I think this is added by server
.....
Return-Path: bounce#domain.com //I think this is cause by returnPath
I set return-path like this:
$mailer->setReturnPath('bounce#domain.com');
I set transport like this:
$emailConfig = $this->getOption('email');
$transport = new Zend_Mail_Transport_Smtp($emailConfig['server'], $emailConfig);
Zend_Mail::setDefaultTransport($transport);
If I don't set returnPath server add returnPath the same as I set From header.
Is it a bug in Zend_Mail or what? What I understand it right that server will add return-path header the same as it's use in MAIL_FROM and setReturnPath shouldn't add header menually, but only save it to use for MAIL_FROM?
It in Zend_Mail_Transport_Smtp change code comment line:
/**
* Sets the Return-Path header of the message
*
* #param string $email
* #return Zend_Mail Provides fluent interface
* #throws Zend_Mail_Exception if set multiple times
*/
public function setReturnPath($email)
{
if ($this->_returnPath === null) {
$email = $this->_filterEmail($email);
$this->_returnPath = $email;
//This line presents in Zend_Framework
//I comment this like I get only one return-path the same as
//set using setReturnPath method of Zend_Mail
//$this->_storeHeader('Return-Path', $email, false);
} else {
/**
* #see Zend_Mail_Exception
*/
require_once 'Zend/Mail/Exception.php';
throw new Zend_Mail_Exception('Return-Path Header set twice');
}
return $this;
}
In Zend you can pass the necessary additional parameter to sendmail by explicitly choosing the transport:
$tr = new Zend_Mail_Transport_Sendmail('-fmail#example.com');
$_mail = new Zend_Mail();
$_mail->setDefaultTransport($tr);
try this:
$mail->addHeader('Return-path', 'email#address.com');
Related
I just tried this example:
// for use PHP Mailer without composer :
// ex. Create a folder in root/PHPMAILER
// Put on this folder this 3 files find in "src"
// folder of the distribution :
// PHPMailer.php , SMTP.php , Exception.php
// include PHP Mailer
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
include dirname(__DIR__) .'/PHPMAILER/PHPMailer.php';
include dirname(__DIR__) .'/PHPMAILER/SMTP.php';
include dirname(__DIR__) .'/PHPMAILER/Exception.php';
// i made a function
/*
*
* Function send_mail_by_PHPMailer($to, $from, $subject, $message);
* send a mail by PHPMailer method
* #Param $to -> mail to send
* #Param $from -> sender of mail
* #Param $subject -> suject of mail
* #Param $message -> html content with datas
* #Return true if success / Json encoded error message if error
* !! need -> classes/Exception.php - classes/PHPMailer.php - classes/SMTP.php
*
*/
function send_mail_by_PHPMailer($to, $from, $subject, $message){
// SEND MAIL by PHP MAILER
$mail = new PHPMailer();
$mail->CharSet = 'UTF-8';
$mail->isSMTP(); // Use SMTP protocol
$mail->Host = 'your_host.com'; // Specify SMTP server
$mail->SMTPAuth = true; // Auth. SMTP
$mail->Username = 'my_mail#your_host.com'; // Mail who send by PHPMailer
$mail->Password = 'your_passord_of_your_box'; // your pass mail box
$mail->SMTPSecure = 'ssl'; // Accept SSL
$mail->Port = 465; // port of your out server
$mail->setFrom($from); // Mail to send at
$mail->addAddress($to); // Add sender
$mail->addReplyTo($from); // Adress to reply
$mail->isHTML(true); // use HTML message
$mail->Subject = $subject;
$mail->Body = $message;
// SEND
if( !$mail->send() ){
// render error if it is
$tab = array('error' => 'Mailer Error: '.$mail->ErrorInfo );
echo json_encode($tab);
exit;
}
else{
// return true if message is send
return true;
}
}
/*
*
* END send_mail_by_PHPMailer($to, $from, $subject, $message)
* send a mail by PHPMailer method
*
*/
// use function :
send_mail_by_PHPMailer($to, $from, $subject, $message);
When calling new PHPMailer() the system throws a error:
Can't find class PHPMailer.
The include of the files works fine. What is wrong?
You could try reading the readme (which should be the first place you look anyway), which tells you the right way to load PHPMailer without composer.
I expect the problem is that you are using include instead of require, and the classes are failing to load, so that when you try to make an instance, it's not defined, giving you the error you're seeing. Your script will not work without those files, so you want it to fail if they can't be loaded.
There's a lesson though - learn to use composer and understand how it works. As a PHP novice, it's the single best thing you can do.
When I'm building and testing my website on local server, I would like to emulate successful sending via phpmailer, so I avoid actually sending emails.
I normally use if ($mail->Send()) { the mail was sent, now do this }.
For local testing I think the best would be to skip the whole phpmailer inclusion, instead of adding a lot of if statements etc.
But skipping phpmailer would then cause php to complain about $mail->Send(), $mail->addAddress('emailaddress') etc.
How could I fake the function (or object/class) so that calls to $mail->Send() are always true, and the rest $mail->something() etc. are just ignored/true, so that no email is sent?
Extend the PHPMailer class and override the public function send().
class UnitTestMailer extends PHPMailer {
public function send() {
return $this;
}
}
class User {
public function __construct(PHPMailer $mailer) {
$this->mailer = $mailer;
}
public function sendActiviation() {
return $this->mailer->send();
}
}
// ... somewhere in your test
public function test_if_from_is_properly_set() {
// ...
$user = new User(new UnitTestMailer);
// ...
$mailer = $user->sendActivation();
$this->assertEquals($expectedFrom, $mailer->From);
}
Why emulate?
I use INI files to provide configuration variables for PHPMailer depending on the environment. Live obviously has the server's mail settings. Local uses my Gmail account credentials to send mail.
You can have the best of both worlds :)
Keep a config.ini file for example somewhere in your working directory (I tend to use root but that's preference) and make sure it's in your .gitignore or similar. Your local version would look something like:
[PHPMailer Settings]
EMAIL_HOST = "smtp.gmail.com"
EMAIL_PORT = 587
EMAIL_SMTPSECURE = "tls"
EMAIL_SMTPAUTH = "true"
EMAIL_USERNAME = "my_email#gmail.com"
EMAIL_PASSWORD = "my_password"
then in your PHP:
$ini = parse_ini_file($_SERVER['DOCUMENT_ROOT'] . "/config.ini", true, INI_SCANNER_TYPED);
// use settings from INI file:
$foo = $ini['PHPMailer Settings']['EMAIL_HOST'];
$bar = $ini['PHPMailer Settings']['EMAIL_PORT'];
Security Bonus
Change the syntax of your INI file to look like the below and rename it to config.ini.php:
; <?php
; die();
; /*
[PHPMailer Settings]
EMAIL_HOST = "smtp.gmail.com"
EMAIL_PORT = 587
EMAIL_SMTPSECURE = "tls"
EMAIL_SMTPAUTH = "true"
EMAIL_USERNAME = "my_email#gmail.com"
EMAIL_PASSWORD = "my_password"
; */ ?>
(remember to use the new filename in your PHP code)
PHP can still parse the settings, but if anyone tried to access the INI file it would be parsed as PHP comments and just show ";"
How can I set the default setFrom field with title in Zend_Mail
If I send mail like this
public function sendActivationEmail($id) {
$mail = new Zend_Mail();
$mail ->addTo('emailId1#gmail.com',"Recepient Name")
->setFrom("emailId1#gmail.com","Site Name")
->setSubject("My Subject")
->setBodyText("Some body msg")
->setBodyHtml("Some body msg")
->send();
}
I get an email in nice format with From Field in mail as "Site Name"
But If I send mail without setFrom, I still get the mail, but the title is "emailId1#gmail.com". I dont want to use SetFrom() just to get "Site From". Is there a way I can set it so that "Site Name" gets picked up by default ?
I have followed this tutorial for setting up my email : http://www.zendcasts.com/introduction-to-zend_mail/2010/02/
Thank you,
If you want to set a default email address for the from attribute, you can use setDefaultFrom() static method like this:
For example, in your boostrap:
protected function _initFromMail(){
// You can get the mail from an init file
Zend_Mail::setDefaultFrom('emailId1#gmail.com', 'Site Name');
}
In your function, the from adress mail is automatically fiiled.
public function sendActivationEmail($id) {
$mail = new Zend_Mail();
$mail ->addTo('emailId1#gmail.com',"Recepient Name")
->setSubject("My Subject")
->setBodyText("Some body msg")
->setBodyHtml("Some body msg")
->send();
}
I would probably just create a subclass of Zend_Mail and use that. Something like the following:
class My_Mail extends Zend_Mail
{
public function __construct($charset = null)
{
parent::__construct($charset);
setFrom('emailId1#gmail.com, 'Site Name');
}
}
Then usage would be:
$mail = new My_Mail();
$mail ->addTo('emailId1#gmail.com','Recipient Name')
->setSubject('My Subject')
->setBodyText('Some body msg')
->setBodyHtml('Some body msg')
->send();
The usual requirements about how to autoload classes in the My_ pseudo-namespace would apply. For example, you could add:
autoloaderNamespaces[] = My_
to your application/config/application.ini
I have a function that sends out site emails (using phpmailer), what I want to do is basically for php to replace all the placheholders in the email.tpl file with content that I feed it. The problem for me is I don't want to be repeating code hence why I created a function (below).
Without a php function I would do the following in a script
// email template file
$email_template = "email.tpl";
// Get contact form template from file
$message = file_get_contents($email_template);
// Replace place holders in email template
$message = str_replace("[{USERNAME}]", $username, $message);
$message = str_replace("[{EMAIL}]", $email, $message);
Now I know how to do the rest but I am stuck on the str_replace(), as shown above I have multiple str_replace() functions to replace the placeholders in the email template. What I would like is to add the str_replace() to my function (below) and get it to find all instances of [\] in the email template I give it and replace it with the placeholders values that I will give it like this: str_replace("[\]", 'replace_with', $email_body)
The problem is I don't know how I would pass multiple placeholders and their replacement values into my function and get the str_replace("[{\}]", 'replace_with', $email_body) to process all the placeholders I give it and replace with there corresponding values.
Because I want to use the function in multiple places and to avoid duplicating code, on some scripts I may pass the function 5 placeholders and there values and another script may need to pass 10 placeholders and there values to the function to use in email template.
I'm not sure if I will need to use an an array on the script(s) that will use the function and a for loop in the function perhaps to get my php function to take in xx placeholders and xx values from a script and to loop through the placeholders and replace them with there values.
Here's my function that I referred to above. I commented the script which may explain much easier.
// WILL NEED TO PASS PERHAPS AN ARRAY OF MY PLACEHOLDERS AND THERE VALUES FROM x SCRIPT
// INTO THE FUNCTION ?
function phpmailer($to_email, $email_subject, $email_body, $email_tpl) {
// include php mailer class
require_once("class.phpmailer.php");
// send to email (receipent)
global $to_email;
// add the body for mail
global $email_subject;
// email message body
global $email_body;
// email template
global $email_tpl;
// get email template
$message = file_get_contents($email_tpl);
// replace email template placeholders with content from x script
// FIND ALL INSTANCES OF [{}] IN EMAIL TEMPLATE THAT I FEED THE FUNCTION
// WITH AND REPLACE IT WITH THERE CORRESPOING VALUES.
// NOT SURE IF I NEED A FOR LOOP HERE PERHAPS TO LOOP THROUGH ALL
// PLACEHOLDERS I FEED THE FUNCTION WITH AND REPLACE WITH THERE CORRESPONDING VALUES
$email_body = str_replace("[{\}]", 'replace', $email_body);
// create object of PHPMailer
$mail = new PHPMailer();
// inform class to use smtp
$mail->IsSMTP();
// enable smtp authentication
$mail->SMTPAuth = SMTP_AUTH;
// host of the smtp server
$mail->Host = SMTP_HOST;
// port of the smtp server
$mail->Port = SMTP_PORT;
// smtp user name
$mail->Username = SMTP_USER;
// smtp user password
$mail->Password = SMTP_PASS;
// mail charset
$mail->CharSet = MAIL_CHARSET;
// set from email address
$mail->SetFrom(FROM_EMAIL);
// to address
$mail->AddAddress($to_email);
// email subject
$mail->Subject = $email_subject;
// html message body
$mail->MsgHTML($email_body);
// plain text message body (no html)
$mail->AltBody(strip_tags($email_body));
// finally send the mail
if(!$mail->Send()) {
echo "Mailer Error: " . $mail->ErrorInfo;
} else {
echo "Message sent Successfully!";
}
}
Simple, see strtrĀDocs:
$vars = array(
"[{USERNAME}]" => $username,
"[{EMAIL}]" => $email,
);
$message = strtr($message, $vars);
Add as many (or as less) replacement-pairs as you like. But I suggest, you process the template before you call the phpmailer function, so things are kept apart: templating and mail sending:
class MessageTemplateFile
{
/**
* #var string
*/
private $file;
/**
* #var string[] varname => string value
*/
private $vars;
public function __construct($file, array $vars = array())
{
$this->file = (string)$file;
$this->setVars($vars);
}
public function setVars(array $vars)
{
$this->vars = $vars;
}
public function getTemplateText()
{
return file_get_contents($this->file);
}
public function __toString()
{
return strtr($this->getTemplateText(), $this->getReplacementPairs());
}
private function getReplacementPairs()
{
$pairs = array();
foreach ($this->vars as $name => $value)
{
$key = sprintf('[{%s}]', strtoupper($name));
$pairs[$key] = (string)$value;
}
return $pairs;
}
}
Usage can be greatly simplified then, and you can pass the whole template to any function that needs string input.
$vars = compact('username', 'message');
$message = new MessageTemplateFile('email.tpl', $vars);
The PHP solutions can be:
usage of simple %placeholder% replacement mechanisms:
str_replace,
strtr,
preg_replace
use of pure PHP templating and conditional logic (short open tags in PHP and alternative syntax for control structures)
Please, find the wide answer at Programmers.StackExchange to find out other approaches on PHP email templating.
Why dont you just make the email template a php file aswell? Then you can do something like:
Hello <?=$name?>, my name is <?=$your_name?>, today is <?=$date?>
inside the email to generate your HTML, then send the result as an email.
Seems to me like your going about it the hard way?
when i send email i get two emails but it should send email to respective emails.
Lopoping problem ?
$array_values = Array
(
[0] => Array
(
[0] => uname1
[1] => fullname1
[2] => email 1
)
[1] => Array
(
[0] => uname2
[1] => fullname2
[2] => email 2
)
)
$f=0;
foreach($array_values as $mail_vars)
{
//$mail->AddReplyTo($mail_vars[2],'RED');
$mail->AddAddress($mail_vars[2], 'sss');
$body .="<br>";
$body .= 'Username: '. $mail_vars[0];
$body .="<br>";
$body .= 'Password: '.$mail_vars[1];
$body .="<br>";
$mail->SetFrom('email', 'FULLNAME');
$mail->Subject = "NEW";
$mail->MsgHTML($body);
//$mail->Send();
$f++;
}
Looking through the source of PHP Mailer, you will need to clear the fields. At least the address, maybe more. Here is the section of code from the PHPMailer class that has the clear functions. You are more than welcomed to look through them and try them etc. This is obviously an alternative to re-instantiating a new object, which may or may not cause a memory leak (depending on how many calls you make to it).
So implementing the clearAddresses code:
$mail->Subject = "NEW";
$mail->MsgHTML($body);
$mail->Send();
$mail->ClearAddresses(); // should reset the To address and remove the first one from it.
I removed the actual code as you just need the description and function name.
/////////////////////////////////////////////////
// CLASS METHODS, MESSAGE RESET
/////////////////////////////////////////////////
/**
* Clears all recipients assigned in the TO array. Returns void.
* #return void
*/
public function ClearAddresses() {
}
/**
* Clears all recipients assigned in the CC array. Returns void.
* #return void
*/
public function ClearCCs() {
}
/**
* Clears all recipients assigned in the BCC array. Returns void.
* #return void
*/
public function ClearBCCs() {
}
/**
* Clears all recipients assigned in the ReplyTo array. Returns void.
* #return void
*/
public function ClearReplyTos() {
}
/**
* Clears all recipients assigned in the TO, CC and BCC
* array. Returns void.
* #return void
*/
public function ClearAllRecipients() {
}
/**
* Clears all previously set filesystem, string, and binary
* attachments. Returns void.
* #return void
*/
public function ClearAttachments() {
}
/**
* Clears all custom headers. Returns void.
* #return void
*/
public function ClearCustomHeaders() {
}
if you look through the php mailer code, there is this useful method ClearAllRecipients() if you want to clear to, cc, and bcc all at once.
You need a:
$mail=new PHPMailer()
in the beginning of your for loop -as it is, the second time through it just messes around with the first email (since a new one isn't created).
As you pointed out body also needs to be reset - in fact using a separated var like that isn't very helpful - better to just supply directly to MsgHTML. Since the content of your email is trivial you may also want to send a plain-text version of the data (depends on your target recipient I guess).
So the updated script:
foreach($array_values as $mail_vars)
{
$mail=new PHPMailer();
$mail->SetFrom('email', 'FULLNAME');
$mail->AddAddress($mail_vars[2], 'sss');
$mail->Subject = "NEW";
$mail->MsgHTML("<br>\nUsername: ".$mail_vars[0]."<br>\nPassword: ".$mail_vars[1]."<br>");
//$mail->Send();
$f++;
}