A Laravel 5.7 project
I have a form where I need to upload 3 images and 2 pdfs in single form.
What I am going for:
Submit the form and save data.
Convert the files uploaded via the user form as a single pdf.
Sending the converted pdf as a mail attachment using code.
Tried like this
public function sendmail(Request $request){
$data["email"]=$request->get("email");
$data["client_name"]=$request->get("client_name");
$data["subject"]=$request->get("subject");
$pdf = PDF::loadView('mails.mail', $data);
try{
Mail::send('mails.mail', $data, function($message)use($data,$pdf) {
$message->to($data["email"], $data["client_name"])
->subject($data["subject"])
->attachData($pdf->output(), "invoice.pdf");
});
}catch(JWTException $exception){
$this->serverstatuscode = "0";
$this->serverstatusdes = $exception->getMessage();
}
if (Mail::failures()) {
$this->statusdesc = "Error sending mail";
$this->statuscode = "0";
}else{
$this->statusdesc = "Message sent Succesfully";
$this->statuscode = "1";
}
return response()->json(compact('this'));
}
In Sales > Invoices when Send Email is clicked, I need a PDF to be attached to the email. I'm using Magento 2.3.3.
$pdf = 'path to pdf';
$this->configureEmailTemplate();
$this->transportBuilder->addTo(
$this->identityContainer->getCustomerEmail(),
$this->identityContainer->getCustomerName()
);
$copyTo = $this->identityContainer->getEmailCopyTo();
if (!empty($copyTo) && $this->identityContainer->getCopyMethod() == 'bcc') {
foreach ($copyTo as $email) {
$this->transportBuilder->addBcc($email);
}
}
//$transport = $this->addAttachment($pdf, $pdfFileName);
$transport = $this->transportBuilder->addAttachment($pdf, 'test');
$transport = $this->transportBuilder->getTransport();
$transport->sendMessage();`
I tried to write addAttachemtment function to the customized transportBuilder page. But it didn't work.
Does anyone know how to do this?
I have a google apps scripts app that gets Gmail message attachments, posts it to DB using JDBC. then on the server, a PHP script gets the data and puts in into a file and attaches it to an email.
the problem is that the files are corrupt when email arrives
here is the google apps script function that gets the attachment content
function getMessageAttachmentsArray(msg){
var GmailAttachments = msg.GmailMessage.getAttachments();
var validAttachments = [];
var attachmentNames = [];
if(GmailAttachments)
{
for(i in GmailAttachments)
{
var gName = GmailAttachments[i].getName();
attachmentNames.push(gName);
var mimeType = GmailAttachments[i].getContentType();
var size = GmailAttachments[i].getSize();
var content = Utilities.base64Encode(GmailAttachments[i].getDataAsString(), Utilities.Charset.UTF_8);
var push = {"content":content,"mimeType":mimeType,"fileName":gName,"size":size,"id":""};
validAttachments.push(push);
}
}
return [validAttachments, attachmentNames];
}
here is the PHP code that generated the email from the file data:
require_once 'smtpmail/classes/class.phpmailer.php';
$mail = new PHPmailer(true);
$email = $argv[1];
$messageid = $argv[2];
$fax_number = $argv[3];
$attachments = array();
//get the attachments for this email
$Sql = "select * from user_attachments where email = '$email' and messageid like '$messageid%'";
$res = mysql_query($Sql);
while($row = mysql_fetch_array($res)){
$return['filename'] = $row['name'];
$return['mime'] = $row['mime_type'];
$content = base64_decode(str_pad(strtr($row['raw_data'], '-_', '+/'), strlen($row['raw_data']) % 4, '=', STR_PAD_RIGHT));
$temp_file = tempnam(sys_get_temp_dir(), 'Fax');
file_put_contents($temp_file, $content);
$return['file'] = $temp_file;
array_push($attachments, $return);
}
try{
$mail->IsSMTP();
$mail->SMTPDebug = 1;
$mail->SetFrom("example#example.com", "example email");
$mail->Subject = '';
$mail->Body = ' '; //put in a blank body to avoid smtp error
$mail->AddAddress($email);
foreach($attachments as $file){
$mail->AddAttachment($file['file'], $file['filename'], 'base64' ,mime_content_type($file['file']));
}
if($mail->send()){
echo "email to $email sent successfully\n";
}else{
echo "error sending email to $email\n";
}
}catch(phpmailerException $e){
echo $e->errorMessage();
}catch(Exception $e){
echo $e->getMessage();
}
When the message is received it shows the attachments but when downloaded I can not open them and there is a message that the file is corrupt or the file extension does not match the file format
what am I doing wrong?
Thanks in advance.
EDIT:
I tried emailing the attachment without posting to the DB, by posting to the server with UrlFetchApp() and the results are the same. clearly, I am doing something wrong with Base64_encode / decode...
maybe the google apps scripts :
Utilities.base64Encode(GmailAttachments[i].getDataAsString(), Utilities.Charset.UTF_8);
creates a different base64 format than PHP base64_decode expects?
p.s.
I tried also with and without 'str_pad' and I still got the same results.
I changed:
Utilities.base64Encode(GmailAttachments[i].getDataAsString(), Utilities.Charset.UTF_8);
to:
Utilities.base64Encode(GmailAttachments[i].getBytes());
and it works
I am trying to send attachments with SendGrid through PHP, but keep getting a corrupted file error when I open the attachment. The error message "We're sorry. We can't open 'file.docx' because we found a problem with its contents" and when I click on the details of the error I see "The file is corrupt and cannot be opened"
My code looks like the below:
$sendGridLoginInfo = $contactViaEmail->getSendGridLoginInfo();
$sendgrid = new SendGrid($sendGridLoginInfo['Username'], $sendGridLoginInfo['Password']);
$mail = new SendGrid\Mail();
//Add the tracker args
$mail->addUniqueArgument("EmailID", $emailID);
$mail->addUniqueArgument("EmailGroupID", $emailGroupID);
/*
* INSERT THE SUBSITUTIONS FOR SEND GRID
*/
foreach ($availableSubstitutions as $availableSubstitution)
{
$mail->addSubstitution("[[" . $availableSubstitution . "]]", $substitutions[$availableSubstitution]);
}
/*
* ADD EACH EMAIL AS A NEW ADD TO
* This makes it BCC (because each person gets their own copy) and each person gets their own individualized email.
*/
foreach ($emailInfo['SendToEmailAddress'] as $toEmail)
{
if ($sendToLoggedInUser)
{
$mail->addTo($adminEmailAddress);
}
else
{
$mail->addTo($toEmail);
}
$trashCount++;
}
//Set the subject
$mail->setSubject($emailInfo['EmailSubject']);
//Instantiate the HTML Purifier (for removing the html)
$config = HTMLPurifier_Config::createDefault();
$config->set('HTML', 'Allowed', '');
$purifier = new HTMLPurifier($config);
$mail->setText($purifier->purify($emailBody));
$mail->setHtml($emailBody);
if ($emailInfo['AttachmentID'])
{
$sql = "SELECT
AttachmentPath
FROM
EmailAttachments
WHERE
EmailAttachments.AttachmentID = :attachmentID";
if ($query = $pdoLink->prepare($sql))
{
$bindValues = array();
$bindValues[":attachmentID"] = $emailInfo['AttachmentID'];
if ($query->execute($bindValues))
{
if ($row = $query->fetch(\PDO::FETCH_ASSOC))
{
$attachment = "";
$mail->addAttachment($sitedb . $row['AttachmentPath']);
}
}
}
}
if ($sendToLoggedInUser)
{
$mail->setFrom($adminEmailAddress);
$mail->setReplyTo($adminEmailAddress);
}
else
{
$mail->setFrom($emailInfo['FromAddress']);
$mail->setReplyTo($emailInfo['ReplyTo']);
}
$mail->setFromName($emailInfo['FromName']);
$sendgrid->web->send($mail);
I've played with the content type and everything else that I can think of and just cannot find out what is causing the attachments to be corrupted.
You need to create an attachment object to add an attachment, you can't use the path directly like you are. SendGrid requires files to be sent as base64 encoded strings.
You'll need to create the attachment object, you could do this as a method:
public function getAttachment($path)
{
if (!file_exists($path)) {
return false;
}
$attachment = new SendGrid\Attachment;
$attachment->setContent(base64_encode(file_get_contents($path)));
$attachment->setType(mime_content_type($path));
$attachment->setFilename(basename($path));
$attachment->setDisposition('attachment');
return $attachment;
}
Then add it to your email:
$attachment = $this->getAttachment($sitedb . $row['AttachmentPath']);
if ($attachment instanceof SendGrid\Attachment) {
$mail->addAttachment($attachment);
}
I've written my own Code Igniter model for sending emails. All was fine until recently when I started to get this error:
Fatal error: Cannot redeclare class phpmailerException in /home/mysite/public_html/subdir/application/libraries/phpmailer/class.phpmailer.php on line 2319
I'm using:
CodeIgniter 2
PHPMailer 5.1
I've tried the following to resolve it:
Added "$mail->SMTPDebug = 0" to turn off errors.
Added: "$mail->MailerDebug = false;"
Modified the PHPMailer to only show errors when SMTPDebug is turned on.
Looked for and removed any echo statements
Added try / catch blocks Tried adding / removing: $mail = new PHPMailer(true);
Here is my controller method (company/contact) which calls my model (message_model):
function contact()
{
//Do settings.
$this->options->task='email';
$this->options->change = 'sent';
$this->options->form_validation='';
$this->options->page_title='Contact Us';
//Import library
include_once('application/libraries/recaptcha/recaptchalib.php');//Include recaptcha library.
//Keys for recaptcha, stored in mainconfig file.
$this->options->publickey = $this->config->item('recaptcha_public');
$this->options->privatekey = $this->config->item('recaptcha_private');
//Form validation
$this->form_validation->set_error_delimiters('<div class="error">', '</div>');
$this->form_validation->set_rules('name_field','Name of problem','trim|required|min_length[3]|max_length[100]');
$this->form_validation->set_rules('desc_field','Description','trim|required|min_length[10]|max_length[2000]');
$this->form_validation->set_rules('email_field','Your email address','trim|required|valid_email');
$this->form_validation->set_rules('recaptcha_response_field','captcha field','trim|required|callback__check_recaptcha');
//If valid.
if( $this->form_validation->run() )
{
//Set email contents.
$message="This is a message from the contact form on ".$this->config->item('site_name')."<br /><br />";
$message.=convert_nl($this->input->post('desc_field'));
$message.="<br /><br />Reply to this person by clicking this link: ".$this->input->post('name_field')."<br /><br />";
$options = array('host'=>$this->config->item('email_host'),//mail.fixilink.com
'username'=>$this->config->item('email_username'),
'password'=>$this->config->item('email_password'),
'from_name'=>$this->input->post('name_field'),
'to'=>array($this->config->item('email_to')=>$this->config->item('email_to') ),
'cc'=>$this->config->item('email_cc'),
'full_name'=>$this->input->post('name_field'),
'subject'=>'Email from '.$this->config->item('site_name').' visitor: '.$this->input->post('name_field'),
'message'=>$message,
'word_wrap'=>50,
'format'=>$this->config->item('email_format'),
'phpmailer_folder'=>$this->config->item('phpmailer_folder')
);
//Send email using own email class and phpmailer.
$result = $this->message_model->send_email($options);
//Second email to sender
//Set email contents.
$message="Thank you for your enquiry, we aim to get a reply to you within 2 working days. In the meantime, please do follow us on www.facebook.com/autismworksuk";
$options = array('host'=>$this->config->item('email_host'),//mail.fixilink.com
'username'=>$this->config->item('email_username'),
'password'=>$this->config->item('email_password'),
'from_name'=>$this->input->post('name_field'),
'to'=>$this->input->post('email_field'),
'full_name'=>$this->input->post('name_field'),
'subject'=>'Email from '.$this->config->item('site_name'),
'message'=>$message,
'word_wrap'=>50,
'format'=>$this->config->item('email_format'),
'phpmailer_folder'=>$this->config->item('phpmailer_folder')
);
//Send email using own email class and phpmailer.
$result = $this->message_model->send_email($options);
//Set result.
if($result==-1)
$this->session->set_flashdata('result', ucfirst($this->options->task).' was not '.$this->options->change.' because of a database error.');
elseif($result==0)
$this->session->set_flashdata('result', 'No changes were made.');
else
$this->session->set_flashdata('result', ucfirst($this->options->task).' was '.$this->options->change.' successfully.');
//Redirect to completed controller.
redirect('completed');
}
//Validation failed or first time through loop.
$this->load->view('company/contact_view.php',$this->options);
}
Here is my model's method to send the emails. It used to work but without any changes I can think of now I get an exception error:
function send_email($options=array())
{
if(!$this->_required(array('host','username','password','from_name','to','full_name','subject','message'),$options))//check the required options of email and pass aggainst provided $options.
return false;
$options = $this->_default(array('word_wrap'=>50,'format'=>'html','charset'=>'utf-8'),$options);
try
{
if(isset($options['phpmailer_folder']))
require($options['phpmailer_folder']."/class.phpmailer.php");
else
require("application/libraries/phpmailer/class.phpmailer.php");//Typical CI 2.1 folder.
$mail = new PHPMailer();
$mail->MailerDebug = false;
//Set main fields.
$mail->SetLanguage("en", 'phpmailer/language/');
$mail->IsSMTP();// set mailer to use SMTP
$mail->SMTPDebug = 0;
$mail->Host = $options['host'];
$mail->SMTPAuth = TRUE; // turn on SMTP authentication
$mail->Username = $options['username'];
$mail->Password = $options['password'];
$mail->FromName = $options['from_name'];//WHo is the email from.
$mail->WordWrap = $options['word_wrap'];// Set word wrap to 50 characters default.
$mail->Subject = $options['subject'];
$mail->Body = $options['message'];
$mail->CharSet = $options['charset'];
//From is the username on the server, not sender email.
if(isset($options['from']))
$mail->From = $options['from'];
else
$mail->From = $mail->Username; //Default From email same as smtp user
//Add reply to.
if(isset($options['reply_to']))
$mail->AddReplyTo($options['reply_to'], $options['from']);
if(isset($options['sender']))
$mail->Sender = $options['sender'];
//Add recipients / to field (required)
if(is_array($options['to']))
{
foreach($options['to'] as $to =>$fn)
$mail->AddAddress($to, $fn);
}
else
{
$mail->AddAddress($options['to']); //Email address where you wish to receive/collect those emails.
}
//Add cc to list if exists. Must be an array
if(isset($options['cc']))
{
if(is_array($options['cc']))
{
foreach($options['cc'] as $to =>$fn)
$mail->AddCC($to, $fn);
}
else
{
log_message('debug', '---->CC field must be an array for use with Message_Model.');
}
}
//Add bcc to list if exists. Must be an array
if(isset($options['bcc']))
{
if(is_array($options['bcc']))
{
foreach($options['bcc'] as $to =>$fn)
$mail->AddBCC($to, $fn);
}
else
{
log_message('debug', '---->BCC field must be an array for use with Message_Model.');
}
}
//Alternative text-only body.
if(isset($options['alt_body']))
$mail->AltBody=$options['alt_body'];
else
$mail->AltBody = htmlspecialchars_decode( strip_tags( $options['message'] ),ENT_QUOTES );//Strip out all html and other chars and convert to plain text.
//Plain/html format.
if(isset($options['format']))
{
if($options['format']=='html')
$mail->IsHTML(true); // set email format to HTML
}
//Send email and set result.
$return['message']='';
if(!$mail->Send())
{
$return['message'].= "Message could not be sent.<br />\n";
$return['message'].= "Mailer Error: " . $mail->ErrorInfo."\n";
$return['result'] = 0;
}
else
{
$return['message'].= "Message has been sent successfully.\n";
$return['result'] = 1;
}
}
catch (phpmailerException $e)
{
log_message('error', '---->PHPMailer error: '.$e->errorMessage() );
}
catch (Exception $e)
{
log_message('error', '---->PHPMailer error: '.$e->errorMessage() );
}
return $return;
}
if (!class_exists("phpmailer")) {
require_once('PHPMailer_5.2.2/class.phpmailer.php');
}
This Code will clear this issue 100%..
Basically one of two things is happening:
You are "including" your PHP code twice somewhere, causing the 2nd time to generate the redeclaration error
You are using "phpmailerException" somewhere else, besides your model. Have you tried to do a "find all" in your IDE for ALL calls to "phpmailerException" - perhaps you used this name in another area for another exception?
require_once("class.phpmailer.php") is better.
Mukesh is right that require_once will solve Sift Exchanges answer #1. However, there is not need to check if the class exists as require_once does that.