I noticed that my server has been returning this error when trying to send email to an invalid domain:
Standard Message: Failed to set sender: user#invaliddomain.coom [SMTP: Invalid response code received from server (code: 553, response: 5.1.8 ... Domain of sender address user#invaliddomain.coom does not exist)]
Standard Code: 10004
DBMS/User Message:
DBMS/Debug Message:
Is there a way to check the domain first before attempting to send the email? I have a feeling I could also handle this on the SMTP server end by squelching this error, but I like the idea of being able to test an email domain first before sending it. Thanks for your ideas!
Here is the pertinent code just for reference (variables are filtered in from a form):
$headers['To'] = $to_address;
$headers['From'] = $from;
$headers['Reply-To'] = $from;
$headers['Subject'] = $subject;
$this->setHTMLBody($body);
$body = $this->get(array('text_charset' => 'utf-8'));
$headers = $this->headers($headers, true);
$message =& Mail::factory('smtp');
$mail = $message->send($to_address,$headers,$body);
You could use Net_DNS2 to determine if the domain exists and if so, send the email on it's merry way.
include "Net/DNS2.php";
$r = new Net_DNS2_Resolver();
try {
$result = $r->query($domain, 'MX');
} catch(Net_DNS2_Exception $e) {
$result = null;
}
if ($result !== null) {
// send email...
}
Naturally, I'd suggest some level of caching so you aren't repeating lookups.
Related
I have a hard time to send multipart MIME message via SMTP using PHP library called MailSo. Provided two examples are limited. No word on how to create headers, message body, multipart MIME message itself and then send it.
Current webmail (Rainloop) is running on MailSo and I want to avoid using 3rd party library on top of MailSo. Going forward all email actions are stored in the Rainloop Actions.php file.
Based on that to create multipart MIME message I should to create $oMessage object (\MailSo\Mime\Message) and I'm able partially do that like to add subject, message ID, custom headers, message body text but going further I'm not able to set MIME boundaries (to store original message body as a boundary as well additional content type as text/plain) not talking about sending $oMessage object via SMTP.
Here is my test code so far:
include 'lib/MailSo/MailSo.php';
echo '<pre>';
$oLogger = \MailSo\Log\Logger::SingletonInstance()
->Add(\MailSo\Log\Drivers\Inline::NewInstance("\r\n", true))
;
$sToEmails = 'Me As Tester <tester#test.com>';
$oToEmails = \MailSo\Mime\EmailCollection::NewInstance($sToEmails);
$sFromEmails = 'Baba Ganush <no-replay#test.com>';
$oFromEmails = \MailSo\Mime\Email::NewInstance($sFromEmails);
$oMessage = \MailSo\Mime\Message::NewInstance();
$oMessage->RegenerateMessageId();
$oMessage->SetXMailer('RainLoop/1.0.0');
$oMessage->SetCustomHeader('test-header','test-header-value');
$oMessage->setSubject("Test message");
$oMessage->AddText('Generated message body goes here...');
$oMessage->SetFrom($oFromEmails);
$oMessage->SetTo($oToEmails);
$oLogger->WriteDump($oMessage);
Well, I have figured out how to send an email message created using MailSo library (w/o any attachments for now)
Example code below
if($oMessage){
$rMessageStream = \MailSo\Base\ResourceRegistry::CreateMemoryResource();
$iMessageStreamSize = \MailSo\Base\Utils::MultipleStreamWriter($oMessage->ToStream(true), array($rMessageStream), 8192, true, true, true);
}
$aToCollection = $oMessage->GetTo();
if ($aToCollection && $oFrom)
{
$sRawBody = #stream_get_contents($rMessageStream);
if (!empty($sRawBody))
{
$sMailTo = trim($aToCollection->ToString(true));
$sMailSubject = trim($oMessage->GetSubject());
$sMailSubject = 0 === strlen($sMailSubject) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue(\MailSo\Base\Enumerations\Encoding::BASE64_SHORT, $sMailSubject);
$sMailHeaders = $sMailBody = '';
list($sMailHeaders, $sMailBody) = explode("\r\n\r\n", $sRawBody, 2);
unset($sRawBody);
$sMailHeaders = \MailSo\Base\Utils::RemoveHeaderFromHeaders($sMailHeaders, array(\MailSo\Mime\Enumerations\Header::TO_,\MailSo\Mime\Enumerations\Header::SUBJECT));
mail($sMailTo, $sMailSubject, $sMailBody, $sMailHeaders);
}
}
I have a sport betting tips website and on every tip that i publish i send an email to every user (about 700 users in total) with SendGrid. The problem comes with the delivery time. The email is delayed even half an hour from the time of send.
Does anyone know why and how could i fix it?
I am sending it with SMTP.
Here is some of my code:
$catre = array();
$subiect = $mailPronostic['subiect'];
$titlu = $mailPronostic['titlu'];
$text = $mailPronostic['text'];
$data = new DateTime($this->_dataPronostic);
foreach($users as $user){
array_push($catre, $user->_emailUser);
}
$data = urlencode($data->format("d-m-Y H:i"));
$echipe = urlencode($this->_gazdaPronostic." vs ".$this->_oaspetePronostic);
$pronostic = urlencode($predictii[$this->_textPronostic]);
$cota = $this->_cotaPronostic;
$mesaj = file_get_contents("http://plivetips.com/mailFiles/mailPronostic.php?text=".urlencode($text)."&titlu=".urlencode($titlu)."&data=$data&echipe=$echipe&pronostic=$pronostic&cota=$cota");
//return mail(null, $subiect, $mesaj, $header);
$from = array('staff#plivetips.com' => 'PLIVEtips');
$to = $catre;
$subject = "PLIVEtips Tip";
$username = 'user';
$password = 'pass';
$transport = Swift_SmtpTransport::newInstance('smtp.sendgrid.net', 587);
$transport->setUsername($username);
$transport->setPassword($password);
$swift = Swift_Mailer::newInstance($transport);
$message = new Swift_Message($subject);
$message->setFrom($from);
$message->setBody($mesaj, 'text/html');
$numSent = 0;
foreach ($to as $address => $name)
{
if (is_int($address)) {
$message->setTo($name);
} else {
$message->setTo(array($address => $name));
}
$numSent += $swift->send($message, $failures);
}
Thx.
how long does the script take to run? I have a feeling the script is taking a long time. If that's the case, I think it is because you are opening a connection for each message.
With SendGrid, you can send a message to 1000 recipients with one connection by using the X-SMTPAPI header to define the recipients. The easiest way to do this to use the official sendgrid-php library and use the setTos method.
Recipients added to the X-SMTPAPI header will each be sent a unique email. Basically SendGrid's servers will perform a mail merge. It doesn't look like your email content varies with each user, but if it does, then you may use substitution tags in the header to specify custom data per recipient.
If you don't want to use sendgrid-php, you can see how to build the header in this example.
I'm new to using EWS from Exchangeclient classes.
I'm looking for a simple example how to send an email with an attachment. I've found examples about how to send an email but not sending an email with an attachment.
This is my script:
$exchangeclient = new Exchangeclient();
$exchangeclient->init($username, $password, NULL, 'ews/Services.wsdl');
$exchangeclient->send_message($mail_from, $subject, $body, 'HTML', true, true);
I have the following soap request.
$CreateItem->MessageDisposition = "SendAndSaveCopy";
$CreateItem->SavedItemFolderId->DistinguishedFolderId->Id = "sentitems";
$CreateItem->Items->Message->ItemClass = "IPM.Note";
$CreateItem->Items->Message->Subject = $subject;
$CreateItem->Items->Message->Body->BodyType = $bodytype;
$CreateItem->Items->Message->Body->_ = $content;
$CreateItem->Items->Message->ToRecipients->Mailbox->EmailAddress = $to;
$CreateItem->Items->Message->Attachments->FileAttachment->AttachmentId = $attach['AttachmentId'];
$CreateItem->Items->Message->Attachments->FileAttachment->Name = $attach['Name'];
$CreateItem->Items->Message->Attachments->FileAttachment->ContentType = $attach['ContentType'];
$CreateItem->Items->Message->Attachments->FileAttachment->ContentId = $attach['AttachmentId'];
$CreateItem->Items->Message->Attachments->FileAttachment->Content = $attach['ContentId'];
$CreateItem->Items->Message->Attachments->FileAttachment->Size = $attach['Size'];
The error I am getting is:
Fatal error: Uncaught SoapFault exception: [a:ErrorSchemaValidation] The request failed schema validation: The required attribute 'Id' is missing.
In order to send email with an attachment you have to first create the Message (Item) without any recipients (and a MessageDisposition of "SendToNone" or something like that) and save it in your Drafts folder. THEN create a request for a CreateAttachment, like so, where $key is the changekey of the item you created earlier (you have to read back the server response and save the changekey somewhere, because the changekey changes for an item with every modification it undergoes):
$attachrequest->ParentItemId->ChangeKey = $key;
$attachrequest->Attachments->FileAttachment->Name = $attachment_name;
$attachrequest->Attachments->FileAttachment->ContentLocation = $attachment;
$attachrequest->Attachments->FileAttachment->Content = $attachment_content;
$attachrequest->Attachments->FileAttachment->ContentType = $attachment_contenttype;
$response = self::$ews->CreateAttachment($attachrequest);
THEN you update the message (with an UpdateItem) to include recipients and so that the MessageDisposition is something like SendToAllAndSaveCopy.
(Disclaimer: I'm using this method now and it's all working fine, except for identifying the right format for Attachments->FileAttachment->Content, which looks like it should be the encoded base64 data of the attachment--but my computer can't open the attachments I'm sending.)
At any rate I believe this is the way to do it, and certainly I have been able to send messages with attachments with it.
I am developing a PHP application that needs to retrieve arbitrary emails from an email server. Then, the message is completely parsed and stored in a database.
Of course, I have to do a lot of tests as this task is not really trivial with all that different mail formats under the sun. Therefore I started to "collect" emails from certain clients and with different contents.
I would like to have a script so that I can send out those emails automatically to my application to test the mail handling.
Therefore, I need a way to send the raw emails - so that the structure is exactly the same as they would come from the respective client. I have the emails stored as .eml files.
Does somebody know how to send emails by supplying the raw body?
Edit:
To be more specific: I am searching for a way to send out multipart emails by using their source code. For example I would like to be able to use something like that (an email with plain and HTML part, HTML part has one inline attachment).
--Apple-Mail-159-396126150
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
The plain text email!
--=20
=20
=20
--Apple-Mail-159-396126150
Content-Type: multipart/related;
type="text/html";
boundary=Apple-Mail-160-396126150
--Apple-Mail-160-396126150
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html;
charset=iso-8859-1
<html><head>
<title>Daisies</title>=20
</head><body style=3D"background-attachment: initial; background-origin: =
initial; background-image: =
url(cid:4BFF075A-09D1-4118-9AE5-2DA8295BDF33/bg_pattern.jpg); =
background-position: 50% 0px; ">
[ - snip - the html email content ]
</body></html>=
--Apple-Mail-160-396126150
Content-Transfer-Encoding: base64
Content-Disposition: inline;
filename=bg_pattern.jpg
Content-Type: image/jpg;
x-apple-mail-type=stationery;
name="bg_pattern.jpg"
Content-Id: <4BFF075A-09D1-4118-9AE5-2DA8295BDF33/tbg.jpg>
/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAASAAA/+IFOElDQ19QUk9GSUxFAAEB
[ - snip - the image content ]
nU4IGsoTr47IczxmCMvPypi6XZOWKYz/AB42mcaD/9k=
--Apple-Mail-159-396126150--
Using PHPMailer, you can set the body of a message directly:
$mail->Body = 'the contents of one of your .eml files here'
If your mails contain any mime attachments, this will most likely not work properly, as some of the MIME stuff has to go into the mail's headers. You'd have to massage the .eml to extract those particular headers and add them to the PHPMailer mail as a customheader
You could just use the telnet program to send those emails:
$ telnet <host> <port> // execute telnet
HELO my.domain.com // enter HELO command
MAIL FROM: sender#address.com // enter MAIL FROM command
RCPT TO: recipient#address.com // enter RCPT TO command
<past here, without adding a newline> // enter the raw content of the message
[ctrl]+d // hit [ctrl] and d simultaneously to end the message
If you really want to do this in PHP, you can use fsockopen() or stream_socket_client() family. Basically you do the same thing: talking to the mailserver directly.
// open connection
$stream = #stream_socket_client($host . ':' . $port);
// write HELO command
fwrite($stream, "HELO my.domain.com\r\n");
// read response
$data = '';
while (!feof($stream)) {
$data += fgets($stream, 1024);
}
// repeat for other steps
// ...
// close connection
fclose($stream);
You can just use the build in PHP function mail for it. The body part doesnt have to be just text, it can also contain mixed part data.
Keep in mind that this is a proof of concept. The sendEmlFile function could use some more checking, like "Does the file exists" and "Does it have a boundry set". As you mentioned it is for testing/development, I have not included it.
<?php
function sendmail($body,$subject,$to, $boundry='') {
define ("CRLF", "\r\n");
//basic settings
$from = "Example mail<info#example.com>";
//define headers
$sHeaders = "From: ".$from.CRLF;
$sHeaders .= "X-Mailer: PHP/".phpversion().CRLF;
$sHeaders .= "MIME-Version: 1.0".CRLF;
//if you supply a boundry, it will be send with your own data
//else it will be send as regular html email
if (strlen($boundry)>0)
$sHeaders .= "Content-Type: multipart/mixed; boundary=\"".$boundry."\"".CRLF;
else
{
$sHeaders .= "Content-type: text/html;".CRLF."\tcharset=\"iso-8859-1\"".CRLF;
$sHeaders .= "Content-Transfer-Encoding: 7bit".CRLF."Content-Disposition: inline";
}
mail($to,$subject,$body,$sHeaders);
}
function sendEmlFile($subject, $to, $filename) {
$body = file_get_contents($filename);
//get first line "--Apple-Mail-159-396126150"
$boundry = $str = strtok($body, "\n");
sendmail($body,$subject,$to, $boundry);
}
?>
Update:
After some more testing I found that all .eml files are different. There might be a standard, but I had tons of options when exporting to .eml. I had to use a seperate tool to create the file, because you cannot save to .eml by default using outlook.
You can download an example of the mail script. It contains two versions.
The simple version has two files, one is the index.php file that sends the test.eml file. This is just a file where i pasted in the example code you posted in your question.
The advanced version sends an email using an actual .eml file I created. it will get the required headers from the file it self. Keep in mind that this also sets the To and From part of the mail, so change it to match your own/server settings.
The advanced code works like this:
<?php
function sendEmlFile($filename) {
//define a clear line
define ("CRLF", "\r\n");
//eml content to array.
$file = file($filename);
//var to store the headers
$headers = "";
$to = "";
$subject = "";
//loop trough each line
//the first part are the headers, until you reach a white line
while(true) {
//get the first line and remove it from the file
$line = array_shift($file);
if (strlen(trim($line))==0) {
//headers are complete
break;
}
//is it the To header
if (substr(strtolower($line), 0,3)=="to:") {
$to = trim(substr($line, 3));
continue;
}
//Is it the subject header
if (substr(strtolower($line), 0,8)=="subject:") {
$subject = trim(substr($line, 8));
continue;
}
$headers .= $line . CRLF;
}
//implode the remaining content into the body and trim it, incase the headers where seperated with multiple white lines
$body = trim(implode('', $file));
//echo content for debugging
/*
echo $headers;
echo '<hr>';
echo $to;
echo '<hr>';
echo $subject;
echo '<hr>';
echo $body;
*/
//send the email
mail($to,$subject,$body,$headers);
}
//initiate a test with the test file
sendEmlFile("Test.eml");
?>
You could start here
http://www.dreamincode.net/forums/topic/36108-send-emails-using-php-smtp-direct/
I have no idea how good that code is, but it would make a starting point.
What you are doing is connecting direct to port 25 on the remote machine, as you would with telnet, and issuing smtp commands. See eg http://www.yuki-onna.co.uk/email/smtp.html for what's going on (or see Jasper N. Brouwer's answer).
Just make a quick shell script which processes a directory and call it when you want e.g. using at crontab etc
for I in ls /mydir/ do cat I | awk .. | sendmail -options
http://www.manpagez.com/man/1/awk/
You could also just talk to the mail server using the script to send the emls with a templated body..
Edit: I have added the code to Github, for ease of use by other people. https://github.com/xrobau/smtphack
I realise I am somewhat necro-answering this question, but it wasn't answered and I needed to do this myself. Here's the code!
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
class SMTPHack
{
private $phpmailer;
private $smtp;
private $from;
private $to;
/**
* #param string $from
* #param string $to
* #param string $smtphost
* #return void
*/
public function __construct(string $from, string $to, string $smtphost = 'mailrx')
{
$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->SMTPDebug = SMTP::DEBUG_SERVER;
$mail->SMTPAutoTLS = false;
$mail->Host = $smtphost;
$this->phpmailer = $mail;
$this->from = $from;
$this->to = $to;
}
/**
* #param string $helo
* #return SMTP
*/
public function getSmtp(string $helo = ''): SMTP
{
if (!$this->smtp) {
if ($helo) {
$this->phpmailer->Helo = $helo;
}
$this->phpmailer->smtpConnect();
$this->smtp = $this->phpmailer->getSMTPInstance();
$this->smtp->mail($this->from);
$this->smtp->recipient($this->to);
}
return $this->smtp;
}
/**
* #param string $data
* #param string $helo
* #param boolean $quiet
* #return void
* #throws \PHPMailer\PHPMailer\Exception
*/
public function data(string $data, string $helo = '', bool $quiet = true)
{
$smtp = $this->getSmtp($helo);
$prev = $smtp->do_debug;
if ($quiet) {
$smtp->do_debug = 0;
}
$smtp->data($data);
$smtp->do_debug = $prev;
}
}
Using that, you can simply beat PHPMailer into submission with a few simple commands:
$from = 'xrobau#example.com';
$to = 'fred#example.com';
$hack = new SMTPHack($from, $to);
$smtp = $hack->getSmtp('helo.hostname');
$errors = $smtp->getError();
// Assuming this is running in a phpunit test...
$this->assertEmpty($errors['error']);
$testemail = file_get_contents(__DIR__ . '/TestEmail.eml');
$hack->data($testemail);
We have a growing mailing list which we want to send our newsletter to. At the moment we are sending around 1200 per day, but this will increase quite a bit. I've written a PHP script which runs every half hour to send email from a queue. The problem is that it is very slow (for example to send 106 emails took a total of 74.37 seconds). I had to increase the max execution time to 90 seconds to accomodate this as it was timing out constantly before. I've checked that the queries aren't at fault and it seems to be specifically the sending mail part which is taking so long.
As you can see below I'm using Mail::factory('mail', $params) and the email server is ALT-N Mdaemon pro for Windows hosted on another server. Also, while doing tests I found that none were being delivered to hotmail or yahoo addresses, not even being picked up as junk.
Does anyone have an idea why this might be happening?
foreach($leads as $k=>$lead){
$t1->start();
$job_data = $jobObj->get(array('id'=>$lead['job_id']));
$email = $emailObj->get($job_data['email_id']);
$message = new Mail_mime();
//$html = file_get_contents("1032.html");
//$message->setTXTBody($text);
$recipient_name = $lead['fname'] . ' ' . $lead['lname'];
if ($debug){
$email_address = DEBUG_EXPORT_EMAIL;
} else {
$email_address = $lead['email'];
}
// Get from job
$to = "$recipient_name <$email_address>";
//echo $to . " $email_address ".$lead['email']."<br>";
$message->setHTMLBody($email['content']);
$options = array();
$options['head_encoding'] = 'quoted-printable';
$options['text_encoding'] = 'quoted-printable';
$options['html_encoding'] = 'base64';
$options['html_charset'] = 'utf-8';
$options['text_charset'] = 'utf-8';
$body = $message->get($options);
// Get from email table
$extraheaders = array(
"From" => "Sender <sender#domain.com>",
"Subject" => $email['subject']
);
$headers = $message->headers($extraheaders);
$params = array();
$params["host"] = "mail.domain.com";
$params["port"] = 25;
$params["auth"] = false;
$params["timeout"] = null;
$params["debug"] = true;
$smtp = Mail::factory('mail', $params);
$mail = $smtp->send($to, $headers, $body);
if (PEAR::isError($mail)) {
$logObj->insert(array(
'type' => 'process_email',
'message' => 'PEAR Error: '.$mail->getMessage()
));
$failed++;
} else {
$successful++;
if (DEBUG) echo("<!-- Message successfully sent! -->");
// Delete from queue
$deleted = $queueObj->deleteById($lead['eq_id']);
if ($deleted){
// Add to history
$history_res = $ehObj->create(array(
'lead_id' => $lead['lead_id'],
'job_id' => $lead['job_id']
)
);
if (!$history_res){
$logObj->insert(array(
'type' => 'process_email',
'message' => 'Error: add to history failed'
));
}
} else {
$logObj->insert(array(
'type' => 'process_email',
'message' => 'Delete from queue failed'
));
}
}
$t1->stop();
}
hard to tell. You should profile your code using xdebug to pintpoint low hanging fruit.
Also I think you might consider using a message queue to process your e-mail(redis/beanstalkd/gearmand/kestrel) asynchronous or using third-party dependency like for example google app engine which is very cheap($0.0001 per recipient/first 1000 emails a day free)/reliable. That will cost you about 10 cent a day when considering your load.
you're facing a couple of different problems.
1.) to send a lot of emails you really need a mailer queue and several mail servers to get mail from that queue and process the mail in turn (round robin style <-- this link is related but not perfectly specific to your needs. [It's enough to get you started]).
2.) your mail is likely not getting to Hotmail/yahoo for one of 2 reasons.
a.) you don't have RDNS properly configured and when the look for your IP (from the heder) it is not mapping back right to your domain in the header. or
b.), you've already been flagged as a spammer on SPAMHAUS or whatever the blacklisting service du jour is.