I'm trying to send a .CSV file with PHP. The file is written to disk before it's sent but when I try to attach the file with file_get_contents(); the structure of the .CSV isn't preseved yet when try and send the file that's created before it's sent I get a resource id (#183) so how can i attach a file which the user can open as a .CSV file? I've made sure the mime type and headers are correct
EDIT
if(!file_exists(_PS_ORDERS_DIR_.$orderDate.'/'.$file_name.'.csv'))
{
if($file = fopen (_PS_ORDERS_DIR_.$orderDate.'/'.$file_name.'.csv', 'x+'))
{
foreach ($list as $fields)
{
fputcsv($file, $fields);
}
$attachment['mime'] = 'application/vnd.ms-excel';
$attachment['content'] = file_get_contents(_PS_ORDERS_DIR_.$orderDate.'/'.$file_name.'.csv');
$attachment['name'] = $order.'order';
Mail::Send(1, 'order_conf', 'Order CSV Attachment', $success, 'dan.farr#gmail.com', CakeToppers, NULL, NULL, $attachment);
return true;
}
If you are using Swift Mailer, there is no need for file_get_contents(), you can just attach the file directly.
From the Swift Mailer documentation:
//Create the attachment
// * Note that you can technically leave the content-type parameter out
$attachment = Swift_Attachment::fromPath('/path/to/image.jpg', 'image/jpeg');
//Attach it to the message
$message->attach($attachment);
So for you that would be:
$attachment = Swift_Attachment::fromPath(_PS_ORDERS_DIR_.$orderDate.'/'.$file_name.'.csv', 'application/vnd.ms-excel');
//Attach it to the message
$message->attach($attachment);
Related
I am working on Laravel file attachment. I have to send CSV file as attachment in mail without downloading the file to my server. When I click the submit button it didnot send email with file attachment.
My Controller:
$data["email"] = $request->recipient_email;
$data["subject"] = 'Cashup Report for '. $venue->name;
$data["bodyMessage"] = $venue->name.' from '.$start.' to '.$end ;
$excel_file = Excel::create(uniqid().'Cashups', function($excel) use($transactions,$start,$end,$venue) {
$excel->sheet('New sheet', function($sheet) use($transactions,$start,$end,$venue) {
$sheet->loadView('excel.cashups', array('transactions' => $transactions, 'start'=> $start, 'end' => $end, 'venue' => $venue));
});
});
//Feedback mail to client
Mail::send('emails.cashups_report', $data, function($message) use ($data,$excel_file){
$message->from(config('mail.from.address'));
$message->to($data["email"]);
$message->subject($data["subject"]);
//Attach PDF doc
$message->attachData($excel_file,'cashups-report.xlsx');
});
I dont know where i am going wrong. I have already put much time over this but didn't find any solution.
Any guidence in this regards will be highly appreciated. Thanks
You can achieve your goal using the code below. I tried my level best to explain everything in the comments of the code.
//function to generate the csv to be attached in your email
public function createCSV()
{
$myData = MyModel::where(myConditions)->get(['col1','col2','col3']);
header('Content-Type: text/csv; charset=utf-8');
//header without attachment; this instructs the function not to download the csv
header("Content-Disposition: filename=myCsvFile.csv");
//Temporarily open a file and store it in a temp file using php's wrapper function php://temp. You can also use php://memory but I prefered temp.
$Myfile = fopen('php://temp', 'w');
//state headers / column names for the csv
$headers = array('col_name1','col_name2','col_name3');
//write the headers to the opened file
fputcsv($Myfile, $headers);
//parse data to get rows
foreach ($myData as $data) {
$row=array(
$data->col1,
$data->col2,
$data->col3,
);
//write the data to the opened file;
fputcsv($Myfile, $row);
}
//rewind is a php function that sets the pointer at begining of the file to handle the streams of data
rewind($Myfile);
//stream the data to Myfile
return stream_get_contents($Myfile);
}
second function: this sends the email to receipients with the csv attached
public function sendEmail()
{
Mail::send('path_to_your_view.My_view', array(''),
function($message){
$message->to(explode(',', env('EMAILS')))
->subject('Email Subject')
->attachData($this->createCSV(), "MyfileName.csv");
});
}
/*......¯\_(ツ)_/¯......
It works on my computer*/
Best of luck! :)
I leave a simple text for fast reading.
I'm trying to figure out how to send a csv file via sendgrid, csv is used with array, it's
fputcsv($output, array('Column 1', 'Column 2', 'Column 3'));
It's not a real file from server, simply to create file and export data to users.
The problem is... addAttachment or setAttachment returned some errors, they requiere where to find a file from path or directory.
How to attach a file without requesting an existing file from directory via sendgrid?
EDIT:
//Function to generate csv file
private function array2csv($array) {
if (count($array) == 0) {
return null;
}
$lista = $array;
ob_start();
$fp = fopen('php://output', 'w');
foreach ($array as $campos) {
fputcsv($fp, $campos);
}
fclose($fp);
return ob_get_clean();
}
//Call a function to send csv file
public function sendCSVFile(){
$data = $this->reqProducts();
//prepareParams is csv templating and formatting function.
$products = $this->prepareParams($data);
$products = $this->array2csv($products);
$body = "Hello, you have an attached file."
$email = new SendGrid\Email();
$email
->addTo('foo#bar.com')
->setFrom('me#bar.com')
->setSubject($body)
->setText($body)
->setHtml('<strong>Hello World!</strong>')
->addAttachment($products);
}
Error output is:
So:
// Setup mail class, recipients and body
$mailer->AddAttachment('/home/mywebsite/public_html/file.zip', 'file.zip');
The AddAttachment function has four arguments:
AddAttachment(PATH_TO_FILE, FILENAME, ENCODING, HEADER_TYPE)
I used to use xmail() and when I added a attachment here, I passed the filename and the content, that should be in it.
Like this:
$xmail->addAttachment('myamazingfile.pdf', $content);
How can I make it work the same way, so when i call AddAttachment() from the PHPmailer class, I can either pass the same or something like it, so I dont need to have a actual file on my server to send?
AddStringAttachment($string,$filename,$encoding,$type)
eg
$mail = new PHPMailer();
$mail->AddStringAttachment($string,$filename,$encoding,$type);
https://phpmailer.github.io/PHPMailer/classes/PHPMailer-PHPMailer-PHPMailer.html#method_addStringAttachment
since that AddAttachment() function is expecting a path rather than byte data, you should do a php convert to temp file function and then pass that path string into your function
$prefix = 'ConvertMediaArgs_'.time().'_';
$tempfile = tempnam( $this->tempdir, $prefix );
// Args file create failure: kill script with TEMPFILEFAIL error
if($tempfile === false) {
die('file could not be created');
}
// Write args as Key=Val (\n) to file
$fullpath = $this->tempdir.$tempfile;
$content = $someContent // <---------------- this is your file's data
$handle = fopen( $tempfile, "w");
fwrite( $handle, $content );
// $fullpath is the path you wanna pass to your function
$xmail->addAttachment( $fullpath, $content );
I am using pipe to program to send emails to a script. Using this script, I can sucessfully save the entire email as a .txt file on my server. The only thing left to do, is figure out how to save any attachment that the email comes in with. (This email address is only given to one trusted source, so security is not an issue)
Working code that saves entire email as .txt file:
$fd = fopen("php://stdin", "r");
$email = ""; // This will be the variable holding the data.
while (!feof($fd)) {
$email .= fread($fd, 1024);
}
fclose($fd);
/* Saves the data into a file */
$fdw = fopen("/home/lmshost22/public_html/pipemail.txt", "w+");
fwrite($fdw, $email);
fclose($fdw);
Can anyone help me with code that simply extracts the attachment (will ALWAYS be a .csv file) and saves it on my server?
Here is the code that the .txt file shows for the attachment:
------=_NextPart_000_0133_01CE0E98.061E7400
Content-Type: application/vnd.ms-excel;
name="leads.csv"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="leads.csv"
ApplicationDetailId,DateCreated,VehicleInfoId,FirstName,MiddleName,LastNa=
me,Suffix,Street,City,State,ZipCode,Email,HomePhoneArea,HomePhonePrefix,H=
omePhoneSuffix,CellArea,CellPrefix,CellSuffix,WorkPhoneArea,WorkPhonePreF=
ix,WorkPhoneSuffix,AmountBorrow,IsVehiclePaidOff,IsVehicleSalvaged,OweAmo=
unt,TitleOwnership,IsInBankruptcy,IsInCreditCounseling,HearOfUs,VehicleIn=
foId,Year,Make,Model,Trim,Miles,Engine,DriveTrain,Transmission,Options,Bo=
ok,ClassCode,Door,FuelType,BodyStyle
4523,2/18/2013 2:56:33 PM,4524,James,,Pruitt,,7900 =
Carmelita,Atascadero,CA,93422,,702,=3D"353",=3D"9760",=3D"",=3D"",=3D"",=3D=
"",=3D"",=3D"",=3D"2500.0000",True,False,0.0000,No =
one,False,False,Google,4524,2001,=3D"Toyota",Tacoma =
Xtracab,PreRunner,200000,V6 3.4 =
Liter,2WD,Automatic,199443~199448~199471~199480~199508~4234190~,0.0000,1,=
0,Gas,Pickup
------=_NextPart_000_0133_01CE0E98.061E7400--
Attachments imply that the message is MIME/Multipart and has a boundary header set which will delimit the various message parts. eg:
Content-Type: multipart/mixed;
boundary="b1_bb1b331cd6dafa1dc6a19e3b2e090b07"
So you want to find that first via something like:
preg_match('/boundary="(.*)"/', $message, $matches);
The message is divided by -- concatenated with the boundary, followed by headers specific to that part, a blank line, and then the data. eg:
--b1_bb1b331cd6dafa1dc6a19e3b2e090b07
Content-Type: application/pdf; name="Invoice-37272.pdf"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="Invoice-37272.pdf"
// base64 data here //
And the message is terminated with '--' . $boundary . '--', eg: --b1_bb1b331cd6dafa1dc6a19e3b2e090b07--
So you can use those two bits of info to break up your messages into their constituent parts and find/save the attachment.
here is my entire PHP file to extract a csv file(email with .csv attachment is piped to this script). The key is you have to decode the text that makes up the file, it is between the boundaries mentioned above.
<?
$home_path = '/home/USERNAME/public_html/DIRECTORY/';
$filename = "FILENAME.TXT"; // TO SAVE THE CONTENTS OF CSV FILE AS TEXT
$sock = fopen ("php://stdin", 'r');
$email = '';
while (!feof($sock)) {
$email .= fread($sock, 10240);
}
fclose($sock);
$encoding1 = explode ("------=_", $email);
$encoding2 = explode ("------=_", $encoding1[2]);
$encoding3 = $encoding2[0];
$encoding4 = explode (".csv", $encoding3);
$encoding5 = explode ("\n\n", $encoding4[2]);
$encoding = base64_decode($encoding5[1]);
$encoding = $encoding . "---" . strlen($encoding);
$fdw = fopen($home_path . $filename . ".txt", "w+");
fwrite($fdw, $encoding);
fclose($fdw);
?>
So:
// Setup mail class, recipients and body
$mailer->AddAttachment('/home/mywebsite/public_html/file.zip', 'file.zip');
The AddAttachment function has four arguments:
AddAttachment(PATH_TO_FILE, FILENAME, ENCODING, HEADER_TYPE)
I used to use xmail() and when I added a attachment here, I passed the filename and the content, that should be in it.
Like this:
$xmail->addAttachment('myamazingfile.pdf', $content);
How can I make it work the same way, so when i call AddAttachment() from the PHPmailer class, I can either pass the same or something like it, so I dont need to have a actual file on my server to send?
AddStringAttachment($string,$filename,$encoding,$type)
eg
$mail = new PHPMailer();
$mail->AddStringAttachment($string,$filename,$encoding,$type);
https://phpmailer.github.io/PHPMailer/classes/PHPMailer-PHPMailer-PHPMailer.html#method_addStringAttachment
since that AddAttachment() function is expecting a path rather than byte data, you should do a php convert to temp file function and then pass that path string into your function
$prefix = 'ConvertMediaArgs_'.time().'_';
$tempfile = tempnam( $this->tempdir, $prefix );
// Args file create failure: kill script with TEMPFILEFAIL error
if($tempfile === false) {
die('file could not be created');
}
// Write args as Key=Val (\n) to file
$fullpath = $this->tempdir.$tempfile;
$content = $someContent // <---------------- this is your file's data
$handle = fopen( $tempfile, "w");
fwrite( $handle, $content );
// $fullpath is the path you wanna pass to your function
$xmail->addAttachment( $fullpath, $content );