I tried to work out this issue but I'm still unable to send an email with its attachment, can someone post some documentation regarding how to do this in code ?

$fid = 123;
$file = file_load($fid);
    
$message = array(
  'headers' => array('Content-Type' => 'text/html'),
  'key' => 'test',
  'to' => 'test@example.com',
  'from' => 'test@example.com',
  'subject' => 'Test email',
  'body' => 'test'
);
$message['params']['attachments'][] = array(
  'filepath' => $file->uri,
  'filename' => $file->filename,
  'filemime' => $file->filemime,
  'list' => TRUE
);

$system = drupal_mail_system('mimemail', 'test');
$system->format($message);
$result = $system->mail($message);

Comments

sgabe’s picture

You need to use drupal_mail() to send messages as the documentation says in the README.txt. The list parameter is unnecessary. You can find further information in the Doxygen documentation of the module.

Torenware’s picture

No offense, but that was not an answer to the question.

The readme has no code example. It is inadequate for the purpose.

Add some working sample code to the readme, and you have an argument.

I've read the development thread for this feature, and the needed info isn't there either. This need documentation, and badly. If you google "Drupal 7" and "attachments", you will see a level of frustration with this issue approaching anger. It really needs a serious solution.

sgabe’s picture

I will add a page to the handbook ASAP.

sgabe’s picture

Category: feature » task
Ross-Hunter’s picture

Is there example code for this yet?

Ross-Hunter’s picture

After a ton of fun figuring this out, here is some example code for sending an email with an attachment using mime mail.

function example_mail($key, &$message, $params) {
  $data['user'] = $params['from'];
  $account = $data['user']->name;

  $file_content = file_get_contents('some/file/path');

  $attachments = array(
     'filecontent' => $file_content,
     'filename' => 'example-' . $account,
     'filemime' => 'application/pdf',
   );

  switch($key) {
    case 'notice':

      $langcode = $message['language']->language;
      $message['subject'] = 'example submission from '. $account;
      $message['body'][] =
        '<p>'. $account .' has submitted an example.</p>';
      $message['params']['attachments'][] = $attachments;
      break;
  }
}

I have a bigger writeup including sending pdfs on my company's blog.

narcisgirona’s picture

Sorry if i'm asking a stupid question..

But what i suppose to do with that code? where i should implement it?

Thanks for you help

Ross-Hunter’s picture

This code would go into a custom module that would be responsible for sending the email. The link I provided talks about it more in detail. My use case was a custom form that users would fill out. Upon submitting the form Drupal would create a node, and then send the user a pdf version of the form they just filled out, as well as send it to administrators based on some other rules I set up in the module.

Ross-Hunter’s picture

double post.

akhilesh.sawarkar’s picture

I tried to send csv file as attachment but its not working for me (using Drupal 7). Email received without attachment.
Here is code from custom module

$message = array(
      'headers' => array(
      'From' => $from,
      'Sender' => $from,
      'Return-Path' => $from,
	  'MIME-Version'=>'1.0',
	  'X-Mailer' => 'Drupal',
	  'Content-Type' => 'text/html; charset=UTF-8;'
	  ),
   'id' => 'pathchange_notice',
   'to' => $to,
   'subject' => $subject,
   'body' => array($message),

	  );
$message['params']['attachments'][] = array(
  'filepath' => file_stream_wrapper_get_instance_by_uri('public://')->getDirectoryPath().'/csv/test.csv',
  'filename' => 'test.csv',
  'filemime' => "text/csv",
  'list' => TRUE
);
$system = drupal_mail_system('mime', 'notice');
$message = $system->format($message);
$system->mail($message);

Please help me.

ghalenir’s picture

#10 Make sure that you have installed and enabled MIME mail module which is need to send email attachment.

dgtlmoon’s picture

I have to agree with this issue, I'm a fairly experienced developer and I am also stumped at times.

Problem is, to use this module , the developers assume you have working knowledge of sending emails the "Drupal 7 way", but on the other hand, people are coming across this module because they read somewhere that they need to this to send attachments - so there is a bit of a disconnect there, I think some proper working example in the README would be great

oadaeh’s picture

For people looking for real world examples, the Drupal 7 compatible versions of both Mass Contact and Basic webmail use Mime Mail for sending messages that include HTML and/or attachments. I believe the Webform module also does, but I haven't looked through the code to be sure.

Also, for those wishing to read Ross' blog posting (in comment #6), here is the new address: http://rapiddg.com/blog-post/drupal-7-html-e-mail-pdf-attachments

oadaeh’s picture

Issue summary: View changes

Added some code

saurabh.tripathi.cs’s picture

You can use php mail in drupal
sample code:

   function sendcustomers_mail($to,$from, $subject, $message,$ordrid) {
    
      
    $my_module = 'sales';
    $my_mail_token = microtime();
    $filename = 'hello.pdf';  
       
    $fileloc = $filename;   
    $message = array(
    'id' => $my_module . '_' . $my_mail_token,
    'to' => $to,
    'subject' => $subject,
    'body' => array($message),
    'headers' => array(
    'From' => $from, 
    'Sender' => $from, 
    'Return-Path' => $from,
    'Content-type' => 'text/html; charset=UTF-8',
     ),
    ); 
     $attache=$message['params']['attachments'][]  = array(
    'filename' =>  "Invoice-".$ordrid.'.pdf',
    'path' => DRUPAL_ROOT.'temp_files_pdf'.'/'.'Invoice-'.$ordrid.'.pdf',
    'filecontent' => file_get_contents('temp_files_pdf'.'/'.'Invoice-'.$ordrid.'.pdf'),
    'mime' => 'application/pdf',
    'Content-type' => 'application/octet-stream',
    'encoding' => 'base64',
    'disposition' => 'attachment',
    'list' => TRUE
    );
    $system = drupal_mail_system($my_module, $my_mail_token);
     unlink('temp_files_pdf'.'/'.'Invoice-'.$ordrid.'.pdf');
    $message = $system->format($message);
    if ($system->mail($message)) {
    return TRUE;
 
    }
    else {
    return FALSE;
 

        }
}
Anybody’s picture

Please have a look at my comment for version problems between beta1 and alpha2... https://drupal.org/node/2113961#comment-8370229 in #2113961: E-Mail Attachments no more work in 7.x-1.x-beta1 and 7.x-1.x-dev but were working before in alpha2

The difference between "filepath" and "filecontent" seems to be important, but seems to be documented poorly!

splitsplitsplit’s picture

Issue summary: View changes

Ok so I couldn't find a module handbook page and I'm not really sure how to make one. But hopefully this'll save people some pain. This is a working run through of setting up the email module I'm using as of beta2.

Caveats

The code was written when I was relatively new so we can probably improve it! Yep I'm spotting shoddy coding as I write this (looking at that terrible validation). Use it as an example of how the email structure works, not for terrible form coding.

I also need to have a read through about how to best format drupal code for this width, as at the moment it's very difficult to read, and working on a widescreen means I'm pretty lax about it.)

Onto the tutorial

So in this tutorial we'll create a module to use a form to send emails with attachments.

The reason I'll go through everything from scratch is to give a baseline. This should hopefully allow you diagnose problems easier.

To use this tutorial you'll need Mimemail, Mail System and the SMTP authentication module. You can probably skip the last one if you have another way of sending emails and you'll have to modify the mail system module part accordingly.

  • Mimemail
  • SMTP Authentication
  • Mail System

Step 1

Install both modules. Then we'll need to do some set-up. You can use whatever mail host you want to send email, however I'd recommend using gmail if you're just getting started as then you can copypasta the settings and know they'll work.

Step 2: Setting SMTP Authentication

Head to Admin > Configuration > SMTP Authentication Support

Then turn the module on here. Set the following values:

SMTP Server: smtp.gmail.com
SMTP Port: 465
Use encrypted protocol: Use SSL
Username: *Gmail email goes here*
Password: *Gmail password goes here*
E-mail from address: The email address you want your email sent from.
E-mail from name: The name you want on your emails.

And finally the reason why this module is incredible.

The test section:

We can enter an email to send a test email. Better still we can tick the enable debug checkbox and it'll print out all the SMTP messages. If you're using Gmail, you'll probably find it won't work and you'll need to set-up an application specific password. You should actually see this error in the debug messages along with a hyperlink to the Google help page on setting it up.

This ability to view the header traffic is super useful in making sure your email delivery system is working.

Step 3: Setting up Mimemail

We want to save attachments and to do that we need mimemail.

So head to Admin > Configuration > Mimemail

Choose the sender name, sender email address (this is actually the same two fields we just filled in, in the last step. Both modules have the ability to set these. The mail system module will let you choose which one to use).

I personally enable Full HTML email and include the site style sheets to format my emails.

Step 4: Set -up a Mail System

Click the new class button.

On the format dropdown you want MimeMailSystem.

On the mail dropdown you want SmtpMailSystem.

Save these settings then select this new class for the new "Site-wide default MailSystemInterface class".

I have the Mime Mail Module Class set to MimeMailSystem. (although I'm not sure what it does).

Step 5: Time to create the module.

It's a basic form module, so I'm going to assume you know about, menu, block, permission hooks etc. and focus just on the form parts.

If you just want to send an email without the form, then you can re-purpose the code that goes in the form_submit.

We're going to have two possible attachments with our email. The first is a file saved on the current users account.

I've previously set-up a file field on the user accounts. It's this file we'll be calling. The file field is called field_user_file_included

The second file is a file the user can upload on the form.

function sendemail_form($form, &$form_state) {
<br />
//The form field for our first file. This one has to be uploaded on the users account.
 $form['user_file_included'] = array(
    '#type' => 'checkbox',
    '#title' => t('User File'),
    '#disabled' => FALSE,
    '#default_value' => TRUE,
  );

//The second form field. This file will need to be uploaded on the form.
$form['upload_file_included'] = array(
    '#type' => 'file',
    '#title' => t('Upload File'),
    '#description' => 'This file has to be a doc, docx, pdf or odf.',
  );
function tellafriend_form_submit($form, &$form_state) {

    //We're going to need to load the current user so we can take the file 
    //from his profile.
    global $user;
    $currentuser = user_load($user->uid);

    //This is setting up variables the email function will need.
    $email = $form_state['email'];
    $params = array();

    //We'll use this variable to validate whether or not the user has uploaded the 
    //file to his profile.
    $user_file_included = 0;

    //Has the user ticked the checkbox to attach the file on their profile
    if ($form_state['values']['user_file_included'] == '1') {
    //If the file exists, store information about it (it's location, name and format)
    //into the params array. This is the array that will hold all the attachments.
     if(array_key_exists('und',$currentuser->user_file_included )) {
      $user_file_included_upload = file_get_contents($currentuser->field_user_file_included['und']['0']['uri']);
      $params['1'] = 
       array(
        'filecontent' => $user_file_included,
        'filename' => $currentuser->field_user_file_included['und']['0']['filename'],
        'filemime' => $currentuser->field_user_file_included['und']['0']['filemime']);
      } else {
     //if the file doesn't exist set our validation variable.
        $user_file_included = 1;
      } 
    };

    //if the file doesn't exists set the form error.
    if ($user_file_included == 1) {
        form_set_error('cv_included', 
          'You haven\'t uploaded a CV. You can upload one on your account page.'
        );
    }

    //if the user has uploaded a file on the file field on the form itself
    if($_FILES['files']['tmp_name']['upload_file_included'] != '') {
      //save the file into the private file directory
      $upload_file_included = file_save_upload('upload_file_included',
                 array(
                   'file_validate_extensions' => array('doc docx pdf odf'), 
                 ),  
             'private://');
      //First grab the contents of the now saved files.
      //then add it to the params array like we did with the other value
      $upload_file_upload = file_get_contents($upload_file_included->uri);
      $params['2'] =  array(
          'filecontent'    => $upload_file_included->uri,
          'filename' => $upload_file_included->filename,
          'filemime' => $upload_file_included->filemime,
                          );
      //I'm going to delete the file once it's been sent, so set a variable so I know it's been set.
      $del_files['upload_file'] = $upload_file_included;
    }
  
    //this is the drupal mail function, the most important part is our params function
    $message = drupal_mail('sendemail', 'notify', $email, language_default(), $params);

    //if a file has been uploaded on the form call the delete function, now that we've sent the email.
    if (isset($del_files)){
      _tellafriend_filedelete($del_files);
    }

    //check the email result array to make sure an email was sent.
    if(!empty($message['result'])) {
            drupal_set_message(t('The email was sent correctly'));
    } else {
            drupal_set_message(t('There was a problem with the application.'));
    }
}
//This is our mail function. We pass in the email array, the message and the
// parameters (attachments). We didn't set a message but you could.

 function sendemail_mail($key, &$message, $params) {
    global $user;
    $currentuser = user_load($user->uid);

     //Setting email headers, subject line and the body. 
    $message['headers']['MIME-Version'] = '1.0';
    $message['headers']['Content-Type'] = 'multipart/mixed; text/html; charset=UTF-8; format=flowed;';
    $message['subject'] = t('A subject line');
    $message['body'][] = "<p>"."You just an email with attachments"."</p>"
    //Adding our attachment array.
    $message['params']['attachments'] = $params;    
  }
//if a file was uploaded delete it.
function _tellafriend_filedelete(&$del_files){
      file_delete($del_files['upload_file']);
}

And that's it. That should give you a working form which sends an email with attachments!

pabloroberto27’s picture

#16 Your step through was too usefull, I had the smtp module installed and was able to send HTML formatted emails using it, but can´t get the attachments work.

The only problem I faced was a couple of errors error returned by the mime mail module, which said that it expects a valid path instead of the string returned by the file_get_contents function.This error can be solved by adding they key 'filepath' to the params array, like this:

      $params['1'] = array(
        'filecontent' => $user_file_included,
        'filename' => $currentuser->field_user_file_included['und']['0']['filename'],
        'filemime' => $currentuser->field_user_file_included['und']['0']['filemime'],
        'filepath' => file_create_url($currentuser->field_user_file_included['und']['0']['uri']),
);

Thanks for the documentation, I would like to see it in the Handbook!

sgabe’s picture

Status: Active » Fixed

I have added an example module.

tostinni’s picture

Thanks a lot.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

eric.chenchao’s picture

I have also added some document on StackOverflow http://drupal.stackexchange.com/a/143571/6423

Anonymous’s picture

wheretoplaygames’s picture

mgantner, thanks for the updated link.

I'm almost thinking it would be easer to just put a link to a file in the emal, and maybe password protect the file/folder. I'm using this for the Entity Event registration.