We have a PHP-based app (running on a t2.medium instance) that sends emails (to opted-in users only) via SES and both are located in the same region. The app was launched earlier this year and the sending of emails worked properly for months. We recently switched to sending via mailgun (so we could get more information on a problem we were having), but we did not change any of our SES settings. (Note: Our account is approved to send 50k emails per hours - we are trying to send several hundred.)
I wrote a adjunct utility for our app, which also sends emails, and I decided to continue using SES for this utility. A simplified version of the code follows. Note that I kept the layout of this test program as close to the actual utility as possible (and it should be obvious that the utility makes a database call, etc.)
<?php
require_once dirname(__FILE__) . '/PHPMailer-master/PHPMailerAutoload.php';
$mail = new PHPMailer;
$mail->isSMTP();
$mail->Host = 'email-smtp.us-west-2.amazonaws.com';
$mail->SMTPAuth = true;
$mail->Username = 'my_user_name';
$mail->Password = 'my_password';
$mail->SMTPSecure = 'tls';
$mail->From = 'from_sender';
$mail->FromName = 'WebTeam';
$mail->IsHTML(true);
$oldt = microtime(true);
while(true) {
$first_name = 'first_name';
$email = 'to_recipient';
$strCnt = 'many';
$subject = "Lots of great new things to buy";
$body = "<p>" . $first_name . ",</p>";
$body = $body . "<p>You have ' . $strCnt . ' new things to buy waiting for you. Don't let them slip by! ";
$body = $body . "Click <a href='http://fake_url.com'>here</a> to see them!</p>";
$body = $body . "<p>The Web Team</p>";
$mail->addAddress($email);
$mail->Subject = $subject;
$mail->Body = $body;
$newt = microtime(true);
echo 'email build done: ' . $newt - $oldt . PHP_EOL;
$oldt = $newt;
if(!$mail->send(true)) {
echo 'error sending email: ' . $mail->ErrorInfo . PHP_EOL;
} else {
$newt = microtime(true);
echo 'email sent: ' . $newt - $oldt . PHP_EOL . PHP_EOL;
$oldt = $newt;
}
$mail->ClearAllRecipients(); // added line
}
?>
Quite simple!
But, here's the rub. When I ran this the first time, the first email took less than one second to send, the second one took 31 seconds, and the third one required 191 seconds. I then added the one more line of code and ran the program again. This time, the first email took 63 seconds to send. After about 20 minutes, I ran the program a third time. This time, the first three emails were sent in less than one second each, but the fourth one took 191 seconds. I then ran it a fifth time, and the first email took 135 seconds to send. (Do note that all of the emails were received.)
What the heck is going on? More importantly, how do I resolve the problem?
This is not SES being slow. This is a documented, deliberate limitation on EC2 itself, with two possible workarounds.
From the SES documentation:
Important
Amazon Elastic Compute Cloud (Amazon EC2) throttles email traffic over port 25 by default. To avoid timeouts when sending email through the SMTP endpoint from EC2, use a different port (587 or 2587) or fill out a Request to Remove Email Sending Limitations to remove the throttle.
http://docs.aws.amazon.com/ses/latest/DeveloperGuide/smtp-connect.html
Related
I am trying to download the subject of all new mails. The mails are stored in an office365 mail account. So far i have the following:
<cfimap
action ="OPEN"
connection = "Test"
password = "xxxx"
port = "993"
secure = "yes"
server = "outlook.office365.com"
stoponerror = "true"
timeout = "10"
username = "xxxx">
<cfimap
action="getHeaderOnly"
folder="Inbox"
connection="Test"
name="getHeaders"
>
<Cfdump var=#getHeaders#>
<cfimap action="close" connection = "Test">
This is ridiculously slow (several minutes). In my situation I only need to download the subject line of all new mails. I do not need anything else. Any thoughts on how to speed up things.
Update
Came up with an alternative solution. See Convert java code to coldfusion code for an alternative to the cfimap tag.
I'm fairly new to PowerShell and brand new (as in, today) to web services and SOAP. A vendor gave us documentation on their web service API that allows the creation of user accounts. I'm trying to use PowerShell to pull our users from SQL Server and send the data to their service. We will need to add users on an ongoing basis.
Below is a pared-down version of what I came up with and it actually seems to work; the vendor told me to include a dry_run parameter while testing and I'm getting a dry_run_success from the response_type.
My question is: Is this even close to being the appropriate way to do it with PowerShell?
# Open ADO.NET Connection to database
$dbConn = New-Object Data.SqlClient.SqlConnection;
$dbConn.ConnectionString = "Data Source=mydbserver;User ID=someuserid;Password=mypassword;Initial Catalog=mydatabase";
$dbConn.Open();
$sql = "select * from mytable";
$dbSqlCmd = New-Object Data.SqlClient.SqlCommand $sql, $dbConn;
$dbRd = $dbSqlCmd.ExecuteReader();
# Create a Web Service Proxy
$proxy = New-WebServiceProxy -Uri https://somedomain.com/service/wsdl
$namespace = $proxy.GetType().NameSpace
$param = New-Object($namespace + ".somemethod")
# Loop through records from SQL and invoke the web service
While ($dbRd.Read())
{
$param.user_id = $dbRd.GetString(0)
$param.password = $dbRd.GetString(1)
$param.display_name = $dbRd.GetString(2)
$request = $proxy.TheMethod($param)
if ($request.response_type -eq 'error')
{
$request.error.extended_error_text
}
}
# Clean up
$dbRd.Close();
$dbSqlCmd.Dispose();
$dbConn.Close();
A couple things you could improve:
Don't use select * in your SQL queries. Always specify the fields you need, in the order you need. As written, if someone were to restructure the table such that the user ID wasn't the first column, you'd have a mess on your hands because you're accessing the fields by their ordinal number
You're apparently storing those passwords in plaintext in your database. Anyone with access to your database knows the credentials for every one of your users. This is a very bad thing. Resolving this could be a very big discussion.
Your code keeps the database connection open until the script completes. Given the scope here, it's probably not going to cause a major problem, but your database access strategy should be to get in, get your data, get out & disconnect as quickly as possible.
$sql = "select user_id, password, display_name from mytable";
$QueryCmd = $dbConn();
$QueryCmd.CommandText = $sql;
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter;
$QueryCmd.Connection = $dbConn;
$SqlAdapter.SelectCommand = $QueryCmd;
$DataSet = New-Object System.Data.DataSet;
$SqlAdapter.Fill($DataSet)
$dbConn.Close();
$dbConn.Dispose();
$MyResults = $DataSet.Tables[0];
$MyResults | foreach-object {
$param.user_id = $_.user_id;
$param.password = $_.password;
$param.display_name = $_.display_name;
$request = $proxy.TheMethod($param);
if ($request.response_type -eq 'error')
{
$request.error.extended_error_text;
}
}
I have followed the instructions of the mailgun, including dots and commas. I installed composer successfully. My domain name is also verified so I wanted to use API for sending emails.
I created a simple application for testing if emails are going or not.
here is the code of sample php application:
<?php
require 'vendor/autoload.php';
use Mailgun\Mailgun;
$mg = new Mailgun("key-********************************");
$domain = "https://api.mailgun.net/v3/mailgun.************.com/messages";
$mg->sendMessage($domain,
array(
'from' => 'noreply#********.com',
'to' => '********#hotmail.com',
'subject' => 'The mailgun is awesome!',
'text' => 'It is so simple to send a message.'));
echo "done";
?>
I get internal server error 500 when I run this file.
When I change the $domain to "mailgun.*****.com" I get emails but in junk folder
I am confused what is happening here.. no apparent fault..
May be some expert will be able to help me out here..
The $domain has to be the same as entered in your settings.
i.e. the domain is mg.domain.com in your mailgun account,
your $domain is domain.com.
Also your from has to be [anything]#domain.com, to be accepted.
My server would communicate with S3. There are two possibilities as far as I understand:
1) Load the file to my server and send it to the user, keeping S3 access only to my server's IP
2) Redirect to S3 while handling authentication on my server
I've understood(I think) how to do #1 from:
Does Amazon S3 support HTTP request with basic authentication
But is there any way to accomplish #2? I want to avoid the latency of first loading the file to my server and then sending it to the user.
I'm not sure how to keep the S3 url protected from public access in #2. Someone might go through my authentication, get a download link, but that link will be publicly accessible.
I'm new to S3 in general, so bear with me if I've misunderstood anything.
Edit: I've looked into signed links with expiration times, but they can still be accessed by others. I would also prefer to use my own authentication so I can allow access to a link only while a user is signed in.
You should try below code, which your server produce an URL which will expire in say 60 seconds, for users to directly download the file from S3 server.
First: Download HMAX.php from here:
http://pear.php.net/package/Crypt_HMAC/redirected
<?php
require_once('Crypt/HMAC.php');
echo getS3Redirect("/test.jpg") . "\n";
function getS3Redirect($objectName)
{
$S3_URL = "http://s3.amazonaws.com";
$keyId = "your key";
$secretKey = "your secret";
$expires = time() + 60;
$bucketName = "/your bucket";
$stringToSign = "GET\n\n\n$expires\n$bucketName$objectName";
$hasher =& new Crypt_HMAC($secretKey, "sha1");
$sig = urlencode(hex2b64($hasher->hash($stringToSign)));
return "$S3_URL$bucketName$objectName?AWSAccessKeyId=$keyId&Expires=$expires&Signature=$sig";
}
function hex2b64($str)
{
$raw = ";
for ($i=0; $i < strlen($str); $i+=2)
{
$raw .= chr(hexdec(substr($str, $i, 2)));
}
return base64_encode($raw);
}
?>
Take a try.
Am doing one project ,
For that my client asked amazon payment gateway ,
So now i started exploring amazon payment gateway ,
This is the first time am looking the amazon payment gateway ,
I have registered in amazon payment gateway,
Please tell me PHP CODE snippet for amazon payment gateway ,
Thanks
Amazon has different payment products. Checkout by Amazon is their usual product, but it works best for products that you actually ship by mail. SimplePay is probably best for electronic goods and services - which I discovered too late. Make sure you sign up for the right thing. :)
Here's the PHP code for a "Pay Now" button for one item using a POST form submission:
// Key from Amazon
$merchant_id = 'your_id';
$aws_access_key_id = 'your_access_key';
$aws_secret_access_key = 'your_secret_access_key';
// Set up cart
$form['aws_access_key_id'] = $aws_access_key_id;
$form['currency_code'] = 'USD';
$form['item_merchant_id_1'] = $merchant_id;
$form['item_price_1'] = $price;
$form['item_quantity_1'] = $quantity;
$form['item_sku_1'] = $sku;
$form['item_title_1'] = $item_name;
ksort($form);
// Encode order as string and calculate signature
$order = '';
foreach ($form as $key => $value) {
$order .= $key . "=" . rawurlencode($value) . "&";
}
$form['merchant_signature'] = base64_encode(hash_hmac('sha1', $order, $aws_secret_access_key, true));
// Return string with Amazon javascript and HTML form
// Assumes you already have jQuery loaded elsewhere on page
// URL's link to live site, not sandbox!
$amazon_order_html =
'<script type="text/javascript" src="https://images-na.ssl-images-amazon.com/images/G/01/cba/js/widget/widget.js"></script>
<form method="post" action="https://payments.amazon.com/checkout/' . $merchant_id . '">';
foreach ( $form as $key => $value ) {
$amazon_order_html .= '<input type="hidden" name="' . $key . '" value="' . $value . '" />';
}
$amazon_order_html .= '<input alt="Checkout with Amazon Payments" src="https://payments.amazon.com/gp/cba/button?ie=UTF8&color=orange&background=white&cartOwnerId=' . $merchant_id . '&size=large" type="image"></form>';
return $amazon_order_html;
For simple pay when account is created, user will be given a sandbox access in which you find the "Merchant code" at this URL : https://sandbox.simplepay.hu/admin/partner/account/id(partnerid)