I'm trying to send an email with an image attachment. I'm able to send the email,but I have no success with displaying the picture, its just black. The php is receiving a base64 string that it is an image. Also I want to do it without storing anything or writing anything on the server. Is there a possible way to do this?
This is what the php looks like.
<?php
$base64 = $_POST['dataURL'];
//define the receiver of the email
$to = 'some#mail.com';
//define the subject of the email
$subject = 'Test email with attachment';
//create a boundary string. It must be unique
//so we use the MD5 algorithm to generate a random hash
$random_hash = md5(date('r', time()));
//define the headers we want passed. Note that they are separated with \r\n
$headers = "From:Francisco Granado\r\nReply-To: webmaster#example.com";
//add boundary string and mime type specification
$headers .= "\r\nContent-Type: multipart/mixed; boundary=\"PHP-mixed-".$random_hash."\"";
//read the atachment file contents into a string,
//encode it with MIME base64,
//and split it into smaller chunks
$attachment = base64_decode($base64);
//define the body of the message.
ob_start(); //Turn on output buffering
?>
--PHP-mixed-<?php echo $random_hash; ?>
Content-Type: multipart/alternative; boundary="PHP-alt-<?php echo $random_hash; ?>"
--PHP-alt-<?php echo $random_hash; ?>
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
This email have attached a image file
For SED_WE analysis purposes.
--PHP-alt-<?php echo $random_hash; ?>
Content-Type: text/html; charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
<h1>SED_WE</h1>
<p>This email have attached a image file </p>
<p>For SED_WE analysis purposes.</p>
--PHP-alt-<?php echo $random_hash; ?>--
--PHP-mixed-<?php echo $random_hash; ?>
Content-Type: image/jpeg; name="attachment.jpeg"
Content-Transfer-Encoding: base64
Content-Disposition: attachment
<?php echo $attachment; ?>
--PHP-mixed-<?php echo $random_hash; ?>--
<?php
//copy current buffer contents into $message variable and delete current output buffer
$message = ob_get_clean();
//send the email
$mail_sent = #mail( $to, $subject, $message, $headers );
//if the message is sent successfully print "Mail sent". Otherwise print "Mail failed"
echo $mail_sent ? "Mail sent" : "Mail failed";
?>
Also here is my js:
$(document).ready(function (e) {
var imgBase64;
function imgToBase64(url, callback, outputFormat) {
var canvas = document.createElement('CANVAS'); //Creates variable containing canvas in the DOM
var canvas_context = canvas.getContext('2d'); //Creates canvas environment (context) in 2 dimensions
var img = new Image; // new Image instance
img.crossOrigin = 'Anonymous'; //Cross origin textures from other URL's are permitted (see http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html) for more information
console.log('ON LOAD IMG');
//Image load trigger, encode image into base64
img.onload = function () {
//Determine canvas height and width
canvas.height = img.height;
canvas.width = img.width;
console.log('Canvas info:\n Height: ' + canvas.height + '\n Width: ' + canvas.width);
//Draws the image raw format
canvas_context.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL(outputFormat || 'image/png'); //THIS IS WHERE THE MAGIC HAPPENS (img encode to base64)
//imgBase64 = dataURL;
$('#show-picture').attr('src', dataURL); //Change source of the #show-picture image tag to the base64 string to show preview to user
console.log(dataURL);
callback.call(this, dataURL); //Callback function #param {dataURL}
// Clean up
canvas = null;
};
img.src = url;
}
//Reads the path to the picture for a preview
function readURL(input) {
if (input.files && input.files[0]) { //if file exist
var reader = new FileReader(); //new instance of the file reader
reader.onload = function (e) { //when the reader loads the chosen file...
imgToBase64(e.target.result, function (dataURL) { //..then the is converted
setDataURL(dataURL);
});
}
reader.readAsDataURL(input.files[0]);
}
}
function setDataURL(dataURL){
imgBase64 = dataURL;
console.log('setDataUrl=>'+imgBase64);
}
$('#take-picture').change(function () {
readURL(this);
console.log('ONLOAD'+imgBase64);
});
$('#uploadImgBtn').on('click',function(){
var base64String= imgBase64.replace(/data:image[^;]+;base64,/,'');
console.log('base64string'+base64String);
$.post('php/mailer.php',base64String,function(data){alert('Success!'); console.log('response: '+data)});
});
});
P.S: I've tried different things from other post, but there's no success or they write on the server, also it's my first time on php so any good suggestion are very welcomed.
In the javascript file where it sends the data to php there was no key name of dataURL, and I needed to remove the data:image/*;base64, out of the string to send the pure base64. So its suppose to be like this:
$('#uploadImgBtn').on('click',function(){
var base64String= imgBase64.replace(/data:image[^;]+;base64,/,'');
console.log('base64string'+base64String);
$.post('php/mailer.php',{dataURL:base64String},function(data){
alert('Success!');
console.log('response: '+data)});
});
Then the php would receive the dataURL and all I needed to do it was chunk_split that base64 string. Like this:
$base64 = $_POST['dataURL'];
...
$attachment = chunk_split($base64);
...
Related
I have a php script that sends me an email. Within this email data, I send base64 image data, but what I would like is that the base64 gets converted into a jpeg which then gets added as an attachment via email.
<?php
header('Access-Control-Allow-Origin: *');
if(isset($_POST['email'])){
$to = 'my#email.com';
$subject = "New submission from ".$_POST['email'];
$message = $_POST['message'];
$image = base64_to_jpeg( $_POST['image'], 'image.jpeg' ); //this is base64 image
$subscribe = $_POST['subscribe'];
$headers = "From: ".$_POST['email']." <".">\r\n"; $headers = "Reply-To: ".$_POST['email']."\r\n";
$headers = "Content-type: text/html; charset=iso-8859-1\r\n";
'X-Mailer: PHP/' . phpversion();
if(mail($to, $subject, $image, $headers)) echo json_encode(['success'=>true]);
else echo json_encode(['success'=>false]);
exit;
}
function base64_to_jpeg($base64_string, $output_file) {
// open the output file for writing
$ifp = fopen( $output_file, 'wb' );
// split the string on commas
// $data[ 0 ] == "data:image/png;base64"
// $data[ 1 ] == <actual base64 string>
$data = explode( ',', $base64_string );
// we could add validation here with ensuring count( $data ) > 1
fwrite( $ifp, base64_decode( $data[ 1 ] ) );
// clean up the file resource
fclose( $ifp );
return $output_file;
}
?>
$image is data:image/png;base64,iVBORw0KGg
The issue I'm having is that when the email gets sent, the email only inclues plain text "image.jpeg" rather than showing the image, or attaching the image...
Any idea how I can fix this?
Thank you.
Passing $image to the body of the mail would obviously send the name, because that's what you're returning from the function.
But if you pass it with an image tag;
mail($to, $subject, '<img src="' . $image . '" alt="'. $image . '">', $headers); // I used PHP template strings to create the img tag
You're surely going to get the data string passed into the mail's body
Here's a screenshot with the link you posted me
This is the complete code I'm running base64_to_jpeg is your function I got from the question
<?php
function base64_to_jpeg($base64_string, $output_file)
{
// open the output file for writing
$ifp = fopen($output_file, 'wb');
// split the string on commas
// $data[ 0 ] == "data:image/png;base64"
// $data[ 1 ] == <actual base64 string>
$data = explode(',', $base64_string);
// we could add validation here with ensuring count( $data ) > 1
fwrite($ifp, base64_decode($data[1]));
// clean up the file resource
fclose($ifp);
return $output_file;
}
$image = base64_to_jpeg(base64_string_from_link, 'image.jpeg')
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Base 64</title>
</head>
<body>
<?php echo '<img src="' . $image . '" alt="' . $image . '">'; ?>
</body>
</html>
I understand your problem now, When you pass the $image to the mail's body, the alt text is showing simply because, the mail doesn't know where to download the image from.
When you're sending images through mail, the image links have to be absolute paths for the mail to know where to download the image from.
Therefore, either you upload that image to your websites file manager and use an absolute path like so, <img src="https://picsum.photos/id/237/200/300">
or
don't convert the image to .jpeg, just pass the base 64 string as the image's src <img src="data:image/png;base64,iVBORw0KGg">
I also saw in your code that you're not concatenating the $headers together rather just resetting the value. (i.e. you're using = instead of .=)
I'm trying to use MailSo library to create MIME message. I have got to the point where next step is to process attachments. Everything is fine when attachments are binary files but when I try to to add plain text attachment as follow
$rResource = "Some plain text goes here";
$sFileName = 'text.txt';
$iFileSize = \strlen("Some plain text goes here");
$bIsInline = false;
$bIsLinked = false;
$sCID = $metadataCID;
$aCustomContentTypeParams = array(\MailSo\Base\Enumerations\Encoding::QUOTED_PRINTABLE_LOWER);
$oMessage->Attachments()->Add(
\MailSo\Mime\Attachment::NewInstance(
$rResource,
$sFileName,
$iFileSize,
$bIsInline,
$bIsLinked,
$sCID,
$aCustomContentTypeParams
)
);
I expect to see that attachment as
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename=text.txt
but it always forcing to base64 neither adding charset to content-type part as
Content-Type: text/plain; name="text.txt"
Content-Disposition: attachment; filename="text.txt"
Content-Transfer-Encoding: base64
Any tips on that?
It looks like MailSo library treats all attachments except message/rfc822 as binaries. It will require to rewrite or extend createNewMessageAttachmentBody() private function.
I'm trying to add an attachment to emails that I draft but cannot seem to get it to work. I've tried to follow the examples here and here but without success.
Here's what I'm able to do so far:
Connect to the Exchange server
Open the mailbox
Draft an html email
Append the email to the mailbox and have it render the html correctly. (when using text/html as the content-type). Using anything else displays the html as plaintext.
As an additional note, after being drafted, the emails are appended to a mailbox on an Exchange 2010 server and are viewed then sent via Outlook 2010.
Below is my mailer class and the code to draft the email.
mailer.php
<?php
class mailer
{
const USER = 'user';
const PASSWORD = 'pass';
const MAILBOX = '{conn}DRAFTS';
// STRING ORDER: $content-type . $from . $to . $cc . $subject . "\r\n\r\n" . $message
public $message;
public $imap_conn;
public $boundary;
function __construct()
{
// Open the message property so we can start appending strings.
$this->message = '';
// Open the IMAP connection
$this->imap_conn = imap_open(self::MAILBOX,self::USER,self::PASSWORD);
}
public function content_type($string_type)
{
$this->message .= "Content-type:{$string_type}\r\n";
}
public function from($string_from)
{
$this->message .= "From:{$string_from}\r\n";
}
public function to($string_to)
{
$this->message .= "To:{$string_to}\r\n";
}
public function cc($string_cc)
{
$this->message .= "Cc:{$string_cc}\r\n";
}
public function mime($float_mime_version)
{
$this->message .= "MIME-Version:{$float_mime_version}\r\n";
}
public function subject($string_subject)
{
$this->message .= "Subject:{$string_subject}\r\n\r\n";
}
public function message($string_message)
{
$this->message .= "{$string_message}\r\n";
}
public function set_boundary($string_boundary)
{
$this->boundary = $string_boundary;
}
public function append()
{
imap_append($this->imap_conn,self::MAILBOX,$this->message,"\\Draft");
imap_close($this->imap_conn);
}
}
?>
Draft code
// A random hash used for the boundary
$rh = md5(date('c',time()));
$data = chunk_split(base64_encode('Testing'));
$m = new mailer;
$m->set_boundary('--PHP-mixed-' . $rh);
$m->content_type('multipart/mixed; boundary="' . $m->boundary . '"');
$m->mime('1.0');
$m->from('from#mail.com');
$m->to('to#mail.com');
$m->cc('cc1#mail.com,cc2#mail.com');
$m->subject('A new email');
$m->message("
{$m->boundary}
Content-Type: text/html; charset=\"utf-8\"
Content-Transfer-Encoding: base64
Testing my <b>HTML</b>
</br>
{$m->boundary}
Content-Type: application/octet-stream; name=\"test.txt\"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=\"test.txt\"
{$data}
{$m->boundary}--
"));
$m->append();
The message before its appended
Content-type:multipart/mixed; boundary="--PHP-mixed-b408f941593cf92b5a8bd365abb4e64f"
MIME-Version:1.0
From:from#mail.com
To:to#mail.com
Cc:cc1#mail.com
Subject:New Message
--PHP-mixed-b408f941593cf92b5a8bd365abb4e64f
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: "base64"
My <b>html</b> content
--PHP-mixed-b408f941593cf92b5a8bd365abb4e64f
Content-Type: application/octet-stream; name="test.txt"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="test.txt"
--PHP-mixed-b408f941593cf92b5a8bd365abb4e64f--
Question: How do I add an attachment to an email drafted with PHP via IMAP?
Answer: In short, the issue was in two places.
Improper placement of newlines (\r\n). A single newline should be after each header and two newlines after each ending header of a section. See Figure 1.
Improper boundaries. Boundaries should start with -- followed by a unique string. The ending boundary of the message should begin and end with -- See Figure 2
Figure 1
Content-Type: text/html\r\n
Content-Encoding: base64\r\n\r\n
"Message text here."\r\n
Figure 2
--unique
Content-Type: text/html\r\n
Content-Encoding: base64\r\n\r\n
HTML stuff here.\r\n
--unique
Content-Type: application/octet-stream\r\n
Content-Disposition: attachment; filename=\"logs.csv\"\r\n
Content-Transfer-Encoding: base64\r\n\r\n
Attachment(s)\r\n
--unique--
I plan on doing a more in depth write-up on this as it took me a very long time to get it right.
It would be helpful to have some more information on your debugging so far. Is the file being read successfully? Does anything make it to the mailbox? It would also help me to see an output of the full message before your final append.
I do not know if this will solve it, but from my successful code and your second example, your message should have an extra filename property, and the values wrapped in quotes.
Content-Type: application/octet-stream; name="test.txt"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="test.txt"
I have a script that access the specified email and fetches mail. $temp->getContent() echos the following..
----boundary_2710_edfb8b44-71c8-49ff-a8cb-88c83382c4ee
Content-Type: multipart/alternative;
boundary=--boundary_2709_dde0dd0e-ba35-4469-949d-5392aec65750 --boundary_2709_dde0dd0e-ba35-4469-949d-5392aec65750
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: base64
PGZvcm0gbWV0aG9k.........this part is base64 encoded and it works fine if i copy and decode it separately.......AgICAgICAgICAgDQoNCjwvZm9ybT4=
----boundary_2709_dde0dd0e-ba35-4469-949d-5392aec65750-- ----boundary_2710_edfb8b44-71c8-49ff-a8cb-88c83382c4ee
Content-Type: multipart/mixed; boundary=--boundary_2711_eca4cfc3-fc62-43d6-b9fb-e5295abbfbe8 ----boundary_2711_eca4cfc3-fc62-43d6-b9fb-e5295abbfbe8 Content-Type: application/pdf;
name=redBusTicket.pdf
Content-Transfer-Encoding: base64
Content-Disposition: attachment Content-ID: JVBERi0xLjIgCiXi48/TIAoxIDAgb2JqIAo8PCAKL1R5cGUgL0NhdGFsb2cgCi9QYWdlcyAy IDAgUiAKL1BhZ2VNb2RlIC9Vc2VOb25lIAovVmlld2VyUHJlZ
Between this content there is base64 encoded part and it works fine if i copy and decode it separately. Also there is a attachment in the mail. How can i get the attached file. The following is my code. when i use the base64_decode directly i get no output.. just a blank page..
$storage = new Zend_Mail_Storage_Imap($imap);
$temp = $storage->getMessage($_GET['mailid']);
echo base64_decode($temp->getContent());
the documentation in zend website is not very good. Need some help!!
It works good for me:
foreach ($mail as $message) {
$content = null;
foreach (new RecursiveIteratorIterator($message) as $part) {
if (strtok($part->contentType, ';') == 'text/plain') {
$content = $part;
break;
}
}
if ($content) {
echo "\n encode: " . $content->contentTransferEncoding;
echo "\n date: " . $message->date;
echo "\n subject: \n" . iconv_mime_decode($message->subject, 0, 'UTF-8');
echo "\n plain text part: \n" . mb_convert_encoding(base64_decode($content), 'UTF-8', 'KOI8-R');
}
}
I have something like this to get the base_64 contents from an email. Try to filter out what you dont need.
if ($email->isMultipart() && $partsCount){
for($i = 1; $i < $email->countParts() +1; $i++) {
$part = $email->getPart($i);
$headers = $part->getHeaders();
if (
array_key_exists('content-description', $headers)
|| array_key_exists('content-disposition', $headers)
){
if (array_key_exists('content-description', $headers)) {
$att = $part->getContent();
$filepath = utf8_encode(DATA_PATH . '/' . $part->getHeader('content-description'));
if (is_file($filepath)) {
unlink($filepath); // deletes previous files with same name
}
$file = fopen($filepath, "w");
fwrite($file, base64_decode($att));
fclose($file);
$attachments[] = $filepath;
}
}
}
}
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);