I just created a mailer class for Zend Framework 2. It uses the Sendmail class.
The problem is that I set the subject of the email with multiple words. Before sending I dump the subject and all the spaces are ok. After sending the email I check my gmail and all the spaces are stripped out of the subject.
When I run the script I get "testemail" as the subject.
Below a part of the class I created :
public function addFile($p_sPath, $p_sMimetype, $p_sFilename){
$rFile = fopen($p_sPath,'rb');
$this->_m_oAttachment = new Mimepart(fread($rFile,filesize($p_sPath)));
$this->_m_oAttachment->type = $p_sMimetype;
$this->_m_oAttachment->filename = $p_sFilename;
$this->_m_oAttachment->disposition = 'attachment';
$this->_m_oAttachment->encoding = Mime::ENCODING_BASE64;
}
public function sendEmail()
{
$aParts = (!is_null($this->_m_oAttachment))
? array($this->_m_oBodymessage, $this->_m_oAttachment)
: array($this->_m_oBodymessage);
$this->_m_oBodypart->setParts($aParts);
$this->_m_oMessage->setEncoding('utf-8')
->setBody($this->_m_oBodypart)
->addFrom($this->_fromAddress, $this->_fromName)
->addReplyTo($this->_fromAddress, $this->_fromName)
->setSubject($this->_subject);
// even here the spaces are still intact.
$this->send($this->_m_oMessage);
}
$oMailer = $this->getLocator()->get('Core\Mailer');
$oMailer->setBodyHtml('mail/mail.phtml', array('aData' => $aData));
$oMailer->setSubject('test email');
$oMailer->setRecipient('jacob#myemail.com', 'jacob');
$oMailer->addFile(realpath(dirname(__file__). '/../../../../../'.$sPath.$sSubfolder.'/'.$sFilename), 'application/pdf', $aData['data']['eventID'].'_'.$aDeclaratie['data']['userID'].'.pdf');
$oMailer->sendEmail();
This is fixed with Zend Framework 2 stable
http://framework.zend.com/issues/browse/ZF2-258
Related
Today I'm trying to connect my Symfony application to a local mail server that running as Microsoft Exchange server.
First, before switching to Symfony my web project was developed with Asp.NET, for some personal reasons I refund the project under Symfony.
In C# this code was working correctly :
public static void MailSender(string server, string fromDisplayName, string fromMailAddress, List<List<KeyValuePair<string,string>>> tos, string subject, string body, List<string> attachments = null, List<List<KeyValuePair<string,string>>> ccs = null, List<List<KeyValuePair<string,string>>> bccs = null)
{
using (MailMessage mailMessage = new MailMessage())
{
mailMessage.From = new MailAddress(fromMailAddress, fromDisplayName);
foreach(List<KeyValuePair<string, string>> to in tos){
mailMessage.To.Add(new MailAddress(to[1].Value.ToString(), to[0].Value.ToString()));
}
if (ccs != null){
foreach(List<KeyValuePair<string, string>> cc in ccs){
mailMessage.CC.Add(new MailAddress(cc[1].Value.ToString(), cc[0].Value.ToString()));
}
}
if (bccs != null){
foreach(List<KeyValuePair<string, string>> bcc in bccs){
mailMessage.CC.Add(new MailAddress(bcc[1].Value.ToString(), bcc[0].Value.ToString()));
}
}
mailMessage.Subject = subject;
mailMessage.Body = body;
mailMessage.IsBodyHtml = true;
if (attachments != null)
{
foreach (string attachment in attachments)
mailMessage.Attachments.Add(new Attachment(attachment));
}
using (SmtpClient smtpClient = new SmtpClient(server))
{
smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
smtpClient.UseDefaultCredentials = true;
smtpClient.Send(mailMessage);
}
}
}
The server url was in the format: myserver.domain.tld.
Also it used the Windows Integrated Authentication.
How can I configure PHP or Symfony (or both) to work with my local Exchange mail server ?
I tried to use this type of url in MAILER_DSN variable:
smtp://user:pass#myserver.domain.tld (user as email address with '%40' for '#' character.
Thanks.
Sorry for this question cause Its a mistake from me, I put MAILER_DSN=smtp://server.tld:25
Also, I commented a line into config/packages/messenger.yaml
this line: Symfony\Component\Mailer\Messenger\SendEmailMessage: async
This second option solve my problem.
If you had another option, I'm aware about it!
Thks.
Starting from version 5.7 Laravel suggests to use the array driver for Mail during testing:
Unfortunately, the documentation tells nothing about this driver. According to the source code, the driver stores all the messages in memory without actually sending them. How to get the stored "sent" messages during unit testing (in order to check them)?
EDIT: With Laravel 9+, use:
$emails = app()->make('mailer')->getSymfonyTransport()->messages();
dd($emails);
Be sure your mail driver is set to array in your .env or phpunit.xml file.
With Laravel 7+ or if you get error Target class [swift.transport] does not exist use this to get the list of emails sent with the array driver:
$emails = app()->make('mailer')->getSwiftMailer()->getTransport()->messages();
$count = $emails->count();
$subject = $emails->first()->getSubject();
$to = $emails->first()->getTo();
$body = $emails->first()->getBody();
Call app()->make('swift.transport')->driver()->messages(). The return value is a collection of Swift_Mime_SimpleMessage objects.
An example of a full PHPUnit test:
public function testEmail()
{
Mail::to('user#example.com')->send(new MyMail);
$emails = app()->make('swift.transport')->driver()->messages();
$this->assertCount(1, $emails);
$this->assertEquals(['user#example.com'], array_keys($emails[0]->getTo()));
}
My custom assertion based on Finesse's answer.
protected function assertMailSentTo($user, $expected = 1)
{
$messages = app('swift.transport')->messages();
$filtered = $messages->filter(function ($message) use ($user) {
return array_key_exists($user->email, $message->getTo());
});
$actual = $filtered->count();
$this->assertTrue(
$expected === $actual,
"Sent {$actual} messages instead of {$expected}."
);
}
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 ";"
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 strtrDocs:
$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?
I wanna try to send mail using cake php. I have no experience of sending mail. So, I don't know where to start. Is it need to make mail server? If need, how to make mail server and how to send mail? Please explain step by step. I really don't know where to start.
I'm using xampp and now I test my site at localhost.
I tested following link:
http://book.cakephp.org/view/1286/Sending-a-basic-message
but error occurred cannot be accessed directly.
and then I add code from the following link:
http://book.cakephp.org/view/1290/Sending-A-Message-Using-SMTP
So, my code is following:
function _sendMail(){
$this->Email->to = 'user#gmail.com';
$this->Email->bcc = array('secret#example.coom');
$this->Email->subject = 'Welcome to our really cool things';
$this->Email->replyTo = 'support#example.com';
$this->Email->from = 'Online Application <app#example.coom>';
$this->Email->template = 'simple_message';
$this->Email->sendAs = 'both';
$this->Email->smtpOptions = array(
'port' =>'25',
'timeout' => '30',
'host' => 'ssl://smtp.gmail.com',
'username' => 'my_mail#gmail.com',
'password' =>'aaa',
);
$this->Email->delivery = 'smtp';
$this->Email->send();
}
but error still occurred. But, I didn't make any mail server.Is that OK?
I have a feeling this is to do with your XAMPP configuration:
Try opening "php.ini", it should be somewhere in your server files.
Search for the attribute called “SMTP” in the php.ini file.Generally you can find the line “SMTP=localhost“. change the localhost to the smtp server name of your ISP. And, there is another attribute called “smtp_port” which should be set to 25.I’ve set the following values in my php.ini file.
SMTP = smtp.wlink.com.np
smtp_port = 25
Restart the apache server so that PHP modules and attributes will be reloaded.
ow try to send the mail using the mail() function:
mail(“you#yourdomain.com”,”test subject”,”test body”);
If you get the following warning:
Warning: mail() [function.mail]: “sendmail_from” not set in php.ini or custom “From:” header missing in C:\Program Files\xampp\htdocs\testmail.php on line 1
Specify the following headers and try to send the mail again:
$headers = ‘MIME-Version: 1.0′ . “\r\n”;
$headers .= ‘Content-type: text/html; charset=iso-8859-1′ . “\r\n”;
$headers .= ‘From: sender#sender.com’ . “\r\n”;
mail(“you#yourdomain.com”,”test subject”,”test body”,$headers);
source: http://roshanbh.com.np/2007/12/sending-e-mail-from-localhost-in-php-in-windows-environment.html
Naming the controller function with a leading underscore is Cake's backwards compatible way of designating that the function should be protected, i.e. that the function should not be accessible as a normal controller action. That means you can't access FooController::_sendMail() using the URL /foo/_sendMail, or any other URL for that matter. You should be seeing this, which IMO is a pretty good error message:
Private Method in UsersController
Error: FooController::_sendMail() cannot be accessed directly.
Remove the leading underscore, that's all. This problem has nothing to do with sending email.
Try:
//load mail component in controller
var $components = array('Mail');
//then do
$this->Email->sendAs="html";
$this->Email->from="some#domain.com";
$this->Email->to="someone#domain.com";
$this->Email->subject="Your subject;
$this->Email->send("Your message);
//Check cakephp manual for more reference: http://book.cakephp.org/
Here is an example code for sending an HTML email with CakePHP's Email component
Ex controller : EmailController.php
<?php
class EmailController extends AppController{
public $components=array('Email');
function send(){
//create an array of values to be replaced in email html template//
$emailValues=array('name'=>'MyName','phone'=>'MyPhone');
$this->set('emailValues',$emailValues);//pass to template //
$this->Email->to = 'to#address.com'; //receiver email id
$this->Email->subject = 'Subject Line';
$this->Email->replyTo = 'reply#address.com'; //reply to email//
$this->Email->from = 'SenderName<sender#address.com>'; //sender
$this->Email->template = 'sample';//email template //
$this->Email->sendAs = 'html';
if($this->Email->send()){
//mail send //
}
}
?>
Now create the email template in folder /Views/Email/html/
ie the template path should be
/Views/Email/html/sample.ctp
sample.ctp
<?php
Hi <?php echo $emailValues['name'];?> <br>
Thanks for sharing your phone number '<?php echo $emailValues['phone'];?>' .
<br>
?>