I want to send out batch mails using SwiftMail or any similar system. The SwiftMailer docs state that:
"Each recipient of the messages receives a different copy with only their own email address on the To: field. An integer is returned which includes the number of successful recipients."
http://swiftmailer.org/docs/batchsend-method
I want to know whether it's possible to find out which email addresses failed, and optionally obtain the error reason/code.
There's a another page in the instructions there that talks about batchsend() failures http://swiftmailer.org/docs/finding-failures and there is an example, and I suspect batchsend will be done exactly the same way.
$mailer = Swift_Mailer::newInstance( ... );
$message = Swift_Message::newInstance( ... )
->setFrom( ... )
->setTo(array(
'receiver#bad-domain.org' => 'Receiver Name',
'other#domain.org' => 'A name',
'other-receiver#bad-domain.org' => 'Other Name'
))
->setBody( ... )
;
//Pass a variable name to the send() method
if (!$mailer->send($message, $failures))
{
echo "Failures:";
print_r($failures);
}
/*
Failures:
Array (
0 => receiver#bad-domain.org,
1 => other-receiver#bad-domain.org
)
*/
Related
I've create a shopify app using Codeigniter 4. It's a carrier service app. The carrier service is created successfully and I can see it in my development store in settings under manage rates but I'm getting error while checking out. It says - Your cart has been updated and the items you added can’t be shipped to your address. Remove the items to complete your order. Below is the code to create the carrier service:
$response = $client->post(
"carrier_services",
[
"carrier_service" => [
'active' => true,
"name" => "Faast Delivery",
"callback_url" => "https://app.faastdelivery.com/shopify/rate",
"service_discovery" => true,
]
]
);
And here is my callback function.
public function rate(){
// log the raw request -- this makes debugging much easier
$filename = time();
$input = file_get_contents('php://input');
file_put_contents($filename.'-input', $input);
// parse the request
$rates = json_decode($input, true);
// log the array format for easier interpreting
file_put_contents($filename.'-debug', print_r($rates, true));
// total up the cart quantities for simple rate calculations
$quantity = 0;
foreach($rates['rate']['items'] as $item) {
$quantity =+ $item['quantity'];
}
// use number_format because shopify api expects the price to be "25.00" instead of just "25"
// overnight shipping is 5.50 per item
$overnight_cost = number_format($quantity * 5.50, 2, '', '');
// regular shipping is 2.75 per item
$regular_cost = number_format($quantity * 2.75, 2, '', '');
// overnight shipping is 1 to 2 days after today
$on_min_date = date('Y-m-d H:i:s O', strtotime('+1 day'));
$on_max_date = date('Y-m-d H:i:s O', strtotime('+2 days'));
// regular shipping is 3 to 7 days after today
$reg_min_date = date('Y-m-d H:i:s O', strtotime('+3 days'));
$reg_max_date = date('Y-m-d H:i:s O', strtotime('+7 days'));
// build the array of line items using the prior values
$output = array('rates' => array(
array(
'service_name' => 'Faast Delivery',
'service_code' => 'FSTD',
'total_price' => $overnight_cost,
"description" => "This is the fastest option by far",
'currency' => 'EUR',
'min_delivery_date' => $on_min_date,
'max_delivery_date' => $on_max_date
),
array(
'service_name' => 'Faast Delivery',
'service_code' => 'FSTD',
'total_price' => $regular_cost,
"description" => "This is the fastest option by far",
'currency' => 'EUR',
'min_delivery_date' => $reg_min_date,
'max_delivery_date' => $reg_max_date
)
));
// encode into a json response
$json_output = json_encode($output);
// log it so we can debug the response
file_put_contents($filename.'-output', $json_output);
// send it back to shopify
header('Content-Type: application/json');
echo $json_output;
// return $json_output;
}
Thanks in advance.
I guess and from my experience that your response took more than 10 secs and for that, a message was returned instead.
please refer to the below timeout period for each request per min:
RPM under 1500: read timeout will be 10 seconds
RPM between 1500 and 3000: read timeout will be 5 seconds
RPM over 3000: read timeout will be 3 seconds
Refrence: Dynamic Timeout for CarrierService API Rate Requests
I'm trying to get rid of the following message in one of my scripts when using the PHPmailer parseAddresses function:
Notice: Unknown: Must use comma to separate addresses: xxx (errflg=3) in Unknown on line 0
$mailer = new PHPMailer(true);
try {
$a = $mailer->parseAddresses('aaa#aaa.aaa xxx');
}
finally {
...
}
I'm using PHP 7.0.8 with the following error handling presets:
declare(strict_types = 1);
error_reporting(E_ALL);
ini_set('display_errors', 'stdout');
I know that I can just stop the errors from being displayed but this doesn't seem to be the proper way to do. And of course I know that the provided email addresses in my example are not correct...
I'm not sure what you're complaining about: it's telling you you have malformed input when you provide malformed input! The way to avoid the error is not to pass in malformed input!
As the error says, it's expecting one or more addresses in comma-delimited RFC822 format (not what you provided), which might be something like:
xxx <aaa#aaa.aaa>, yyy <bbb#aaa.aaa>
If you don't provide data in that format, it will complain, as you're seeing. This is covered in the docs on the parseAddress method.
Are you expecting it to do something else?
PHPMailer writes notices to output, so you could start an output buffer and just flush it after your call. Something like:
$mailer = new PHPMailer(true);
try {
ob_start();
$a = $mailer->parseAddresses('aaa#aaa.aaa xxx');
//$notices = ob_get_contents();
ob_end_clean();
}
finally {
...
}
I had to deal with the same issues. Simply created a homemade solution that does mostly the same thing in a more flexible way. For anyone that is interested:
/**
* split_addresses Split a list of email addresses with potential validation
* Similar concept as PHPMailer->parseAddresses, but more forgiving
* #param $list - a list of comma delimited email addresses in simple or RFC822 format
* #param $default_name an optional name to add if not present
* #param $validate logical var to indicate to only accept validated emails
* #author Jacques Amar
* #copyright 2019 Amar Micro Inc.
*/
function split_addresses($list, $default_name='', $validate=true) {
$valid_arr = [];
if (empty($list)) { return $valid_arr; }
$split_arr = preg_split('/\s*,\s*/', $list);
foreach ($split_arr as $email_candidate) {
// Validate email_candidate if the form "first last <adrs#email.com>"
$actual_name = $default_name;
$actual_email = $email_candidate;
if (preg_match('/\s*(.+)\s*\<\s*([^#]+#.+)\s*\>/', $email_candidate, $actual_emails) == 1) {
$actual_name = $actual_emails[1];
$actual_email = $actual_emails[2];
}
if ($validate) {
if (filter_var($actual_email, FILTER_VALIDATE_EMAIL)) {
$valid_arr[] = ['address' => $actual_email, 'name' => $actual_name];
}
} else {
$valid_arr[] = ['address' => $actual_email, 'name' => $actual_name];
}
}
return $valid_arr;
}
Should be self explanatory
I am using PHPMailer and use AddBCC to send to most of my addresses (only use 1 required in AddAddress). It seems to work okay (no errors), but I have found that it isn't saving (or sending to) all of the addresses that I process with $mail->AddBCC. It skips some of them, yet keeps others. So, when I do a print_r($mail->getBccAddresses()), I can see that it only has some of the email addresses. I am processing my lists of addresses in small groups, so I can control things better, so I wouldn't think there'd be any problems like this. I am including the applicable code from my program:
<?php session_start();
require '../PHPMailer/PHPMailerAutoload.php';
$mail = new PHPMailer;
$emailist_cnt = 3;
for ($i=1; $i<= $emailist_cnt; $i++) {
//loop to gather email addresses into array $emailistAry[][]
}
// First, set up email message and required parameters.
$toname = "Grp-members";// Unused mailbox name
$fromname = "Webmaster";
$replyname ="Grpwebmaster";
$fromaddr = $fromname."#mydomain.org";
$toaddr = $toname."#mydomain.org";
$rplyaddr = $replyname."#gmail".".com";
$subject = "-- Website Update--";
$note1 = "New content has been added to the website";
$note2 = "Go check it out, if you want to stay up-to-date:";
$message = "Greetings HLCA Member! ".$note1." ".$note2;
// Set mail environment variables
$mail->isSMTP();
$mail->Host = 'smtp.hiddenlakeonline.org';
$mail->SMTPAuth = true;
$mail->Username = $fromname."#".$domain.".org";
$mail->Password = $webpass;
$mail->SMTPSecure = 'tls';
$mail->Port = 587;
// Set mail details that remain constant for every recipient
$mail->SetFrom($fromaddr);
$mail->AddAddress($toaddr);
$mail->AddReplyTo($rplyaddr);
$mail->Subject = $subject;
$mail->Body = $message;
$max_emails = 25; // max num emails per list
for ($i=1; $i <= $emailist_cnt; $i+=1) {
for ($j=1; $j <= $max_emails; $j+=1) {
// Addresses in current list will be added to BCC param.
if ($emailistAry[$i][$j] != '') {
$mail->AddBCC($emailistAry[$i][$j]); // add email to BCC }
} // for j loop
echo "would send to email list here. ";
print_r($mail->getBccAddresses());
// Clear cumulative recipient list for next loop
$mail->clearBCCs();
} // for i loop
?>
As you can see, I'm just doing a loop to add BCC entries. But, when I print out the getBCCaddresses array, there is always at least one email missing from each list. Is there a bug in PHP Mailer? Or am I doing something wrong?
I have seen a similar post (without any code) on another site (sourceforge.net?), but the question never got answered. Otherwise, there hasn't been anything similar that could help. Hopefully someone on here knows something about this.
Here are some results I get using echo outputs:
i,j,adding this email: 1,1,ImxEarth#gmail.com
i,j,adding this email: 1,2,heffxdog#me.com
i,j,adding this email: 1,3,imxearth#gmail.com
i,j,adding this email: 1,4,Aaronx72#yahoo.com
print: Array ( [0] => Array ( [0] => ImForEarth#gmail.com [1] => ) [1] => Array ( [0] => heffdog#me.com [1] => ) [2] => Array ( [0] => AaronTW72#yahoo.com [1] => ) )
Is it possible that phpMailer prevents duplicate addresses in BCC array?
I think I found my answer! It appears that AddBCC will only add unique email addresses to its array. So if an email address already exists in the BCCaddresses array, then the Mail->AddBCC('email') statement will not add it again. This becomes apparent when testing, because we often need to use duplicates to create a good size batch of emails. Well, you can process the duplicates, but they won't be added to the BCC parameter and won't be mailed more than once. Thx to all that responded!
I have to show message after insert some data in database. I'm using Kohana. Is there a way to do that with flash messages? It's better than header refresh.
Well sort of. You could use the Session::get_once() function. But this only let you retrieve a variable once, and you cannot use it again in the same request. While you want a flash message to persist a full request cycle. To manage that you'll need a wrapper class, something like this.
class Flash {
private $session;
private $messages = array();
private static $_instance; // Singleton object
public static function instance() {
if ( ! isset( self::$_instance ) ) {
self::$_instance = new Flash();
}
return self::$_instance;
}
private function __construct() {
$this->session = Session::instance();
$this->messages['current'] = $this->session->get_once('flash');
if( ! is_array($this->messages['current'] ) ) {
$this->messages['current'] = array();
}
}
public function add( $key, $message === null ) {
if ( is_null( $message ) ) {
$message = $key;
$key = null;
}
$this->messages['new'][$key] = $message;
$this->session->set('flash', $this->messages['new'] );
return true;
}
public function get( $item = null ) {
if( $item === null ) {
return $this->messages['current'];
}
if( ! array_key_exists($item, $this->messages['current']) ) {
return null;
}
return $this->messages['current'][$item];
}
}
Usage:
$flash = Flash::instance();
$flash->add('A random message');
$flash->add('some_key', 'Some message');
$flash->get(); // array( 0 => 'A random message', 'some_key' => 'Some message')
$flash->get('some_key'); // 'A Random message'
What it does basically is on initialization it retrieves the current message from the session, using the get_once() function. The variable is nou out of the Session object, so it will only last this request. Everytime you add a variable, it will immediately persisted to the Session object.
There is just one problem; if you are using ajax calls, the messages will only be available on the initial php request, not on subsequent ajax calls. And there is also no restriction whatsoever on what kind of variable you are storing (but it must be serializable). You'll have to build in some checks for that too.
warning: the class is not tested, so it would surprise me if you do not get a syntax error ;)
And to go a step further: you would need an extra refresh anyway. The request flow should be like this imo:
Request 1: User is presented form
Request 2: User posts the form, which is processed. Data is inserted in database. When done, user is redirected
Request 3: A confirmation page is shown (can be "thank you", or the detail page, whatever).
You would set the flash message in request 2, and show it in 3. I would not directly show the thank you page on request 2, because when the user refreshes, the form will be posted again.
Use this module. Works perfectly :)
I'm trying to log in a user as part of a form submit, but why is the following not working:
$user = db_fetch_object(db_query("SELECT * FROM users WHERE mail = '%s' AND pass = '%s'", $mail, md5($pass)));
if ($user) {
// Authenticate user and log in
$params = array(
'name' => $user->name,
'pass' => trim($user->pass)
);
// Authenticate user
$account = user_authenticate($params);
}
if I dump $user I can see the correct values, but if I dump the account it's empty.
You are passing the hashed password to ´user_authenticate()´, while the function expects the clear password (it will hash it itself indirectly when loading the account via ´user_load()´).
So changing your $params array declaration to
$params = array(
'name' => $user->name,
'pass' => $pass
);
should make your example work.
BTW, you could use user_load() yourself to avoid querying the database directly:
$user = user_load(array('mail' => $mail, 'pass' => trim($pass), 'status' => 1));
(The 'status' => 1 will restrict results to active users - you can leave that out, of course, if you really want to allow log ins to disabled accounts ;)