Swift Mailer tutorial

Swift Mailer is a fantastic library for sending email with php. Discuss this library or ask any questions about it here.

Moderators: Chris Corbyn, General Moderators

JeffBell
Forum Newbie
Posts: 15
Joined: Thu Feb 01, 2007 8:17 am

Swift Mailer tutorial

Post by JeffBell »

After searching on Google and Yahoo, I have been unable to find any sort of tutorial explaining how to implement Swift Mailer as a contact form.
http://www.swiftmailer.org/

I have been to the official site and there is documentation aimed at developers who are able to make (probably reasonable) assumptions, but there is not really a low-level walkthrough about how to use the library to drive a contact form. In fact, it seems to have more information for folks trying to integrate it into their web application. (I saw info about CakePHP, for example, which I do not understand).

Here is a link to the 'basic instructions' which I do not understand.
http://www.swiftmailer.org/docs/tutorials/basics

Where does this code go? How do I use it? Does it just dump *any* form data into a text email or ?

I'd like to use it with a somewhat typical contact form: first name, last name, address, city, state, zip, phone, email address, maybe a radio button, maybe a dropdown select, maybe a textarea, definitely an upload button which should include the object as an attachment. Upon submission, it gets mailed to one or more pre-defined addresses. It'd be very nice if there were instructions on how to manipulate the format of the email (something clean and organized instead of "firstname = Jeff, lastname = Bell, variable=value" dumps).

I don't imagine it's as simple as

Code: Select all

form action="swiftmailer.php"
and suddenly everything works magically.

Can anyone point me in the right direction for some kind of step-by-step tutorial or explanation of how to use SwiftMailer? I'm somewhat capable of following clear instructions or examples.

I'm happy to share an example of a PHP mail script that does have sufficient information for newbies/non-programmers, just so you can understand what I refer to.
http://www.dagondesign.com/articles/sec ... er-script/

Unfortunately, that nicely documented implementation does include the ability to add attachments and other goodies which Swift Mailer appears to have. Hence, my interest in using Swift.

Thanks for your help.
User avatar
TheMoose
Forum Contributor
Posts: 351
Joined: Tue May 23, 2006 10:42 am

Post by TheMoose »

You would set your form action to the page that you want to handle sending the email. The code example is the code you would put inside the email handler (ie, form action='mypage.php', put that code in mypage.php).

Code: Select all

$swift->send('recipient@address.com', 'sender@address.com', 'The subject', 'The body');
That's where the email is actually being sent. Just fill out the required pieces and you have an email. If you want to have a little bit more format to your email, you can do something along the lines of:

Code: Select all

$body = "Hello  " . $_POST['name'] . "!";
$swift->send('recipient@address.com', 'sender@address.com', 'Good Morning!', $body);
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

I will improve the documentation over time. Right now I'm working on the library itself but because it's only me developing the library and maintaining the documentation on a purely voluntary "on my own time" basis things may not move as quickly as people would like. I'm sorry about that :(

However, I would suggest that you should perhaps try getting to grasps with the basics of PHP and forms (using $_POST, $_GET etc) by reading some more generic tutorials at php.net and by searching Google until I can find time to improve the documentation.

I'm moving documentation to a wiki which I can perhaps put some trust (of course I can :)) in users to edit in the long run.

Have you looked at general contact form tutorials? The Swift part is basic once you know how a contact form would generally be implemented with something like the mail() function.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

If I get time when I get home from work I'll post a tutorial here.
JeffBell
Forum Newbie
Posts: 15
Joined: Thu Feb 01, 2007 8:17 am

Post by JeffBell »

Thanks for the replies. I appreciate the the responses, because I get the idea that Swift Mailer is very flexible for people who have more complicated needs like list management, newsletters, or other large/frequent tasks whereas I want a fairly simple contact form to allow website visitors to email me.

I'll take a look at some generic documentation on POST, compare that to what I see in the Dagon code, and try to piece something together.

It seems the basic idea is
1. Design the form (of course)
2. Submit the action to a PHP document (of course)
3. In that document #2, you have to catch the POSTed variables and values somehow.
4. Temporarily store the uploaded attachment somewhere?
5. Use the Swift Mailer to run some anti-spam / anti-injector routine
6. Use the Swift Mailer to write the variables/values into the body (which can be designed however you like)
7. Use the Swift Mailer to actually attach the attachment
8. Use the Swift Mailer to make the headers (using the TO/SUBJECT/SMTP defined in #2 but inserting the FROMNAME/EMAIL from the user input)
9. Use the Swift Mailer to send the mail to me ("instantiate the connection" I think was the term)

Is that roughly correct as an overview?
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

That's roughly correct, but it's actually even simpler than that. You needn't think about injection, headers or storing the attachment anywhere. PHP and Swift will both do most of that work for you. All you need to do is put the POST data into the relevant methods Swift uses. Since formmail seems to be the only thing out there for sending emails from forms I'm semi-considering writing a wrapper myself and putting it in the library.

Here's an option for the procedural programmer...

First you need to create the form. If it will send attachments, make sure to set the enctype to "multipart/form-data". Set the action attribute to point to a PHP script which we'll create in a few moments. I'm making the attachment upload optional here. I'll call the file form.php and it will send data to mail_handler.php.

Code: Select all

<form action="mail_handler.php" method="post" enctype"multipart/form-data">
    <div class="row">
        <div class="label">Your name*:</div>
        <div class="field"><input type="text" name="user_name" /></div>
    </div>
    <div class="row">
        <div class="label">Your e-mail*:</div>
        <div class="field"><input type="text" name="email" /></div>
    </div>
    <div class="row">
        <div class="label">Subject*:</div>
        <div class="field"><input type="text" name="subject" /></div>
    </div>
    <div class="row">
        <div class="label">Attachment:</div>
        <div class="field"><input type="file" name="attachment" /></div>
    </div>
    <div class="row">
        <div class="label">Comments*:</div>
        <div class="field"><textarea name="comments"></textarea></div>
    </div>
    <div class="row">
        <div class="label">&nbsp;</div>
        <div class="field"><input type="submit" name="submit" value="Send" />
    </div>
</form>
Now you need to create the script which will send the email. Make sure you have uploaded the Swift library to the web server so that you can use it in your script.

The script will:
  • 1. Start a session so if we redirect we don't lose entered data in the form
    2. Fix any mess PHP made with magic_quotes on
    3. Copy POST data into the session so we can use it on the form page again if there's a problem
    4. Load in the Swift files
    5. Check if all POST data was sent that was required
    6. Check if the email address is in a valid format
    7. Check if the file upload was performed and no errors occured (file too big etc)
    8. Connect to the SMTP server
    9. Construct the message body using the POST data
    10. Attach the file if it was uploaded
    11. Add the message body
    12. Send the email to your address
    13. Redirect to a success page if everything worked or go back to the form page with an error if there was a problem
In the script, we'll open a <?php tag immediately and we *won't* output anything at all because we are going to send HTTP headers to redirect the browser once our work is done.

Code: Select all

<?php

/** 1 **/
session_start();

/** 2 **/
//See if evil magic_quotes is enabled, and fix problems if it is
$quotes_on = (get_magic_quotes_gpc() || get_magic_quotes_runtime());
if ($quotes_on)
{
    foreach ($_POST as $key => $value)
    {
        $_POST[$key] = stripslashes($value);
    }
}

/** 3 **/
$_SESSION["post"] = $_POST;

/** 4 **/
//Load in the required Swift files
require_once "classes/Swift.php";
require_once "classes/Swift/Connection/SMTP.php";

/** 5 **/
//Create an empty array where we can catch any fields which were not filled in
$fields_not_set = array();

//Check if all POST data was sent, redirect with an error if not
if (empty($_POST["user_name"])) $fields_not_set[] = "user_name";
if (empty($_POST["email"])) $fields_not_set[] = "email";
if (empty($_POST["subject"])) $fields_not_set[] = "subject";
if (empty($_POST["comments"])) $fields_not_set[] = "comments";

//If $fields_not_set contains any values, then something wasn't filled in. Time to redirect.
if (!empty($fields_not_set))
{
    //Read further down to see how we'll modify form.php to handle the error
    header("Location: form.php?error=incomplete&fields=" . implode(",", $fields_not_set));
    exit();
}

//Copy the POST data to standard globals
$user_name = $_POST["user_name"];
$email = $_POST["email"];
$subject = $_POST["subject"];
$comments = $_POST["comments"];

/** 6 **/
//This is a RegExp I've adopted for validating email addresses.  NOTE that it's NOT RFC compliant.
// Use another regexp at your own choice
$email_re = '(?#Start of dot-atom
                )[-!#\$%&\'\*\+\/=\?\^_`{}\|~0-9A-Za-z]+(?:\.[-!#\$%&\'\*\+\/=\?\^_`{}\|~0-9A-Za-z]+)*(?#
                End of dot-atom)(?:@(?#Start of domain)[-0-9A-Za-z]+(?:\.[-0-9A-Za-z]+)*(?#End of domain))?';

//Now check if the email address they gave is valid, redirect back to the form if not
if (!preg_match($email_re, $email))
{
    header("Location: form.php?error=email_invalid");
    exit();
}

/** 7 **/
$attachment_data = array();
//Now check if there's an attachment they've sent
if (!empty($_FILES["attachment"]))
{
    //If an attachment was sent, but there was an error, redirect
    if ($_FILES["attachment"]["error"] != 0)
    {
        header("Location: form.php?error=attachment_failed");
        exit();
    }
    else $attachment_data = $_FILES["attachment"];
}

/** 8 **/
//Everything looks ok to send an email, create an instance of Swift
$swift = new Swift(new Swift_Connection_SMTP("your.smtp.server.tld"));

/** 9 **/
//Now build your message body
$body = "A message was sent from " . $user_name . " with the title '" . $subject . "'";
if (!empty($attachment_data))
{
    $body .= "\r\nAn attachment with the name '" . $attachment_data["name"] . "' was added";
}

/** 10 **/
//Attach any files if they were sent
// PHP stores files in a temporary location and cleans up itself, so we'll just read the temporary file
if (!empty($attachment_data))
{
    $attachment_str = file_get_contents($attachment_data["tmp_name"]);
    //Check if we need to remove slashes (again!!)
    if ($quotes_on)
    {
        $attachment_str = stripslashes($attachment_str);
    }
    $swift->addAttachment(
        $attachment_str, $attachment_data["name"], $attachment_data["type"]);
}

/** 11 **/
//Add the email body
$swift->addPart($body);

/** 12 **/
//Try sending the email.
// Redirect to success page on success, or form on failure
if ($swift->send("your@address.com", $email, $subject))
{
    unset($_SESSION["post"]); //It worked, we have no reason to keep this data
    $swift->close();
    header("Location: success.php"); /** 13 **/
    exit();
}
else
{
    $swift->close();
    header("Location: form.php?error=runtime_error"); /** 13 **/
    exit();
}


//End of script
For the sake of clarity and brevity, earlier I didn't mention how we'd make the form deal with errors, so lets look at modifying it to do that.

First we'll make sure we start a session at the top of the page, because we don't want the user to have to type everything out again.

Code: Select all

<?php

session_start();

?>
Make sure there's no whitespace at all before that opening <?php tag or it won't work.

Now, we'll make a function to "paint" any already submitted values into the form value calling it in the form's value attributes.

Code: Select all

function paint_value($field)
{
    if (!empty($_SESSION["post"][$field]))
    {
        echo $_SESSION["post"][$field];
    }
    else { echo ""; }
}
We also need to display error messages on the page, so we'll add some code for that too. Putting it all together, the form now looks like this.

Code: Select all

<?php

//Start session
session_start();

//Function to display the values in the fields
function paint_value($field)
{
    if (!empty($_SESSION["post"][$field]))
    {
        echo $_SESSION["post"][$field];
    }
    else { echo ""; }
}

//Check if errors were sent
if (!empty($_GET["error"]))
{
    switch ($_GET["error"])
    {
        case "incomplete":
            $field_labels = array("user_name" => "Name", "email" => "E-mail address", "subject" => "Subject", "comments" => "Comments");
            $incomplete = explode(",", $_GET["fields"]);
            ?><div class="error">All required fields (*) were not completed.  Please check the following fields:
                <ul>
                    <?php foreach ($incomplete as $field) {
                        if (isset($field_labels[$field])) { echo "<li>" . $field_labels[$field] . "</li>"; }
                    } ?>
                </ul></div><?php
            break;
        case "email_invalid":
            ?><div class="error">The email address entered does not appear to be a valid format</div><?php
            break;
        case "attachment_failed":
            ?><div class="error">The attachment upload failed.  Perhaps the file is too large?</div><?php
            break;
        case "runtime_error":
            ?><div class="error">There was a problem processing your request.  Please try again later.</div><?php
            break;
    }
}

?>
<form action="mail_handler.php" method="post" enctype"multipart/form-data">
    <div class="row">
        <div class="label">Your name*:</div>
        <div class="field"><input type="text" name="user_name" value="<?php paint_value("user_name"); ?>" /></div>
    </div>
    <div class="row">
        <div class="label">Your e-mail*:</div>
        <div class="field"><input type="text" name="email" value="<?php paint_value("email"); ?>" /></div>
    </div>
    <div class="row">
        <div class="label">Subject*:</div>
        <div class="field"><input type="text" name="subject" value="<?php paint_value("subject"); ?>" /></div>
    </div>
    <div class="row">
        <div class="label">Attachment:</div>
        <div class="field"><input type="file" name="attachment" /></div>
    </div>
    <div class="row">
        <div class="label">Comments*:</div>
        <div class="field"><textarea name="comments"><?php paint_value("comments"); ?></textarea></div>
    </div>
    <div class="row">
        <div class="label">&nbsp;</div>
        <div class="field"><input type="submit" name="submit" value="Send" />
    </div>
</form>
The above should give you a fairly solid working form-mail set up. Obviously, I could have gone into a lot more detail, but if you don't know much about PHP development it would be too overwhelming as the above is fairly lengthy as it is.

Hopefully it will clear a few things up though.

Cheers,

Chris
JeffBell
Forum Newbie
Posts: 15
Joined: Thu Feb 01, 2007 8:17 am

Post by JeffBell »

A quick update to let you know I think I've understood what you laid out here.

Currently, I'm debugging to try to get the example to run.

Once that's done, then I'll try modifying some bits and pieces based on what I learn by experimenting... and from the documentation because I am already guessing it will be more valuable/understandable to me once I've gotten this leg-up you're giving me.

I can't say how much I appreciate the instruction. I'll probably be back before long with an intelligent question and two stupid ones as I get this test version to work.
JeffBell
Forum Newbie
Posts: 15
Joined: Thu Feb 01, 2007 8:17 am

Post by JeffBell »

I think I am stumped by a problem I cannot figure a way around.

Code: Select all

Warning: preg_match() [function.preg-match]: Unknown modifier '[' in mail_handler.php on line 57

Warning: Cannot modify header information - headers already sent by (output started at mail_handler.php:57) in mail_handler.php on line 59
Now, I searched around on the error preg_match and understand there is, basically, an unexpected "[" character at line 57, which I checked and there is no [ bracket on that line (or on line 59).

However, there is a [ in the RegExp above on line 53 which is used in the variable $email_re (the email validator) and that is referenced/called/used in line 57. So, it must be the RegExp, where there are two in the code. The first [ appears to be a functional bracket that's holding the other characters, if I guess right. Which means it must be the second [ which causes the problem. I read that the problem character should be "escaped" with a backslash, so I tried that. It continued to fail.

Code: Select all

$email_re = '(?#Start of dot-atom
                )[-!#\$%&\'\*\+\/=\?\^_`{}\|~0-9A-Za-z]+(?:\.\[-!#\$%&\'\*\+\/=\?\^_`{}\|~0-9A-Za-z]+)*(?#
                End of dot-atom)(?:@(?#Start of domain)[-0-9A-Za-z]+(?:\.[-0-9A-Za-z]+)*(?#End of domain))?';
After some thought, I decided to put the backslash on the first [ which didn't work either.

Code: Select all

$email_re = '(?#Start of dot-atom
                )\[-!#\$%&\'\*\+\/=\?\^_`{}\|~0-9A-Za-z]+(?:\.[-!#\$%&\'\*\+\/=\?\^_`{}\|~0-9A-Za-z]+)*(?#
                End of dot-atom)(?:@(?#Start of domain)[-0-9A-Za-z]+(?:\.[-0-9A-Za-z]+)*(?#End of domain))?';
Stoically, I then proceed to try backslashing them both, but that didn't work either.

Code: Select all

$email_re = '(?#Start of dot-atom
                )\[-!#\$%&\'\*\+\/=\?\^_`{}\|~0-9A-Za-z]+(?:\.\[-!#\$%&\'\*\+\/=\?\^_`{}\|~0-9A-Za-z]+)*(?#
                End of dot-atom)(?:@(?#Start of domain)[-0-9A-Za-z]+(?:\.[-0-9A-Za-z]+)*(?#End of domain))?';
So, there it is. I'll need to understand how to properly escape the character, so it doesn't foul up line 57.

Further, I'm under the assumption that if this error is fixed, then the note about headers being set in 59 won't be a problem, but I'm off to pre-emptively research that next.
JeffBell
Forum Newbie
Posts: 15
Joined: Thu Feb 01, 2007 8:17 am

Post by JeffBell »

JeffBell wrote: Further, I'm under the assumption that if this error is fixed, then the note about headers being set in 59 won't be a problem, but I'm off to pre-emptively research that next.
Just looked into that and it's a whitespace/extra line problem. I checked both files very carefully and the ONLY whitespace appearing before a php tag is on line 26 of form.php where there are some tabs/indentations. After removing that whitespacing/tabbing, the second error about headers still appears.

Perhaps my initial guess was right; it's caused by the RegExp. I'll wait for a little help.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Doh... that was just a token for part of a regexp since I use it in larger expressions:

Code: Select all

//Now check if the email address they gave is valid, redirect back to the form if not 
if (!preg_match('/^' . $email_re . '$/', $email)) 
{ 
    header("Location: form.php?error=email_invalid"); 
    exit(); 
}
PS: I didn't test the code. Was in a rush to type it. It was supposed to be a guide rather than a copy & paste example ;)
JeffBell
Forum Newbie
Posts: 15
Joined: Thu Feb 01, 2007 8:17 am

Post by JeffBell »

I don't mean to drain your time or anything. Since I'm not really too bright in these areas, I thought it best to crack the example into shape first before going it alone and building what I really want. Okay, I'll update accordingly. Thank you very much for the help.

I'm not sure what these changes do, but I did lookup preg_match at
http://www.php.net/preg_match

It seems that the ^ hat is some kind of "assertion" (a term I do not understand the context of).
pattern can contain assertions such as ^, $ or (?<=x)

Also, I noticed on that page, in the comments, there are a couple people talking about these RegExp functions as email filters. Of course, I don't quite understand what it *means* but they also use the /^ with the "pattern" -- however, they don't use $/ with the "string" so I'll have to search for more examples of this to learn.

(Incorrect edit removed.)
Last edited by JeffBell on Thu Feb 01, 2007 5:48 pm, edited 1 time in total.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Here are the tested working scripts. All I changed was the regexp which was already posted earlier, and a missing "=" iin enctype in the form.

Code: Select all

<?php 

/** 1 **/ 
session_start(); 

/** 2 **/ 
//See if evil magic_quotes is enabled, and fix problems if it is 
$quotes_on = (get_magic_quotes_gpc() || get_magic_quotes_runtime()); 
if ($quotes_on) 
{ 
    foreach ($_POST as $key => $value) 
    { 
        $_POST[$key] = stripslashes($value); 
    } 
} 

/** 3 **/ 
$_SESSION["post"] = $_POST; 

/** 4 **/ 
//Load in the required Swift files 
require_once "classes/Swift.php"; 
require_once "classes/Swift/Connection/SMTP.php"; 

/** 5 **/ 
//Create an empty array where we can catch any fields which were not filled in 
$fields_not_set = array(); 

//Check if all POST data was sent, redirect with an error if not 
if (empty($_POST["user_name"])) $fields_not_set[] = "user_name"; 
if (empty($_POST["email"])) $fields_not_set[] = "email"; 
if (empty($_POST["subject"])) $fields_not_set[] = "subject"; 
if (empty($_POST["comments"])) $fields_not_set[] = "comments"; 

//If $fields_not_set contains any values, then something wasn't filled in. Time to redirect. 
if (!empty($fields_not_set)) 
{ 
    //Read further down to see how we'll modify form.php to handle the error 
    header("Location: form.php?error=incomplete&fields=" . implode(",", $fields_not_set)); 
    exit(); 
} 

//Copy the POST data to standard globals 
$user_name = $_POST["user_name"]; 
$email = $_POST["email"]; 
$subject = $_POST["subject"]; 
$comments = $_POST["comments"]; 

/** 6 **/ 
//This is a RegExp I've adopted for validating email addresses.  NOTE that it's NOT RFC compliant. 
// Use another regexp at your own choice 
$email_re = '(?#Start of dot-atom 
                )[-!#\$%&\'\*\+\/=\?\^_`{}\|~0-9A-Za-z]+(?:\.[-!#\$%&\'\*\+\/=\?\^_`{}\|~0-9A-Za-z]+)*(?# 
                End of dot-atom)(?:@(?#Start of domain)[-0-9A-Za-z]+(?:\.[-0-9A-Za-z]+)*(?#End of domain))?'; 

//Now check if the email address they gave is valid, redirect back to the form if not 
if (!preg_match('/^' . $email_re . '$/', $email)) 
{ 
    header("Location: form.php?error=email_invalid"); 
    exit(); 
} 

/** 7 **/ 
$attachment_data = array(); 
//Now check if there's an attachment they've sent 
if (!empty($_FILES["attachment"]["tmp_name"])) 
{ 
    //If an attachment was sent, but there was an error, redirect 
    if ($_FILES["attachment"]["error"] != 0) 
    { 
        header("Location: form.php?error=attachment_failed"); 
        exit(); 
    } 
    else $attachment_data = $_FILES["attachment"]; 
} 

/** 8 **/ 
//Everything looks ok to send an email, create an instance of Swift 
$swift = new Swift(new Swift_Connection_SMTP("mail.w3style.co.uk")); 

/** 9 **/ 
//Now build your message body 
$body = "A message was sent from " . $user_name . " with the title '" . $subject . "'"; 
if (!empty($attachment_data)) 
{ 
    $body .= "\r\nAn attachment with the name '" . $attachment_data["name"] . "' was added"; 
} 

/** 10 **/ 
//Attach any files if they were sent 
// PHP stores files in a temporary location and cleans up itself, so we'll just read the temporary file 
if (!empty($attachment_data)) 
{ 
    $attachment_str = file_get_contents($attachment_data["tmp_name"]); 
    //Check if we need to remove slashes (again!!) 
    if ($quotes_on) 
    { 
        $attachment_str = stripslashes($attachment_str); 
    } 
    $swift->addAttachment( 
        $attachment_str, $attachment_data["name"], $attachment_data["type"]); 
} 

/** 11 **/ 
//Add the email body 
$swift->addPart($body); 

/** 12 **/ 
//Try sending the email. 
// Redirect to success page on success, or form on failure 
if ($swift->send("chris@w3style.co.uk", $email, $subject)) 
{ 
    unset($_SESSION["post"]); //It worked, we have no reason to keep this data 
    $swift->close(); 
    header("Location: success.php"); /** 13 **/ 
    exit(); 
} 
else 
{ 
    $swift->close(); 
    header("Location: form.php?error=runtime_error"); /** 13 **/ 
    exit(); 
} 


//End of script

Code: Select all

<?php 

//Start session 
session_start(); 

//Function to display the values in the fields 
function paint_value($field) 
{ 
    if (!empty($_SESSION["post"][$field])) 
    { 
        echo $_SESSION["post"][$field]; 
    } 
    else { echo ""; } 
} 

//Check if errors were sent 
if (!empty($_GET["error"])) 
{ 
    switch ($_GET["error"]) 
    { 
        case "incomplete": 
            $field_labels = array("user_name" => "Name", "email" => "E-mail address", "subject" => "Subject", "comments" => "Comments"); 
            $incomplete = explode(",", $_GET["fields"]); 
            ?><div class="error">All required fields (*) were not completed.  Please check the following fields:
                <ul> 
                    <?php foreach ($incomplete as $field) { 
                        if (isset($field_labels[$field])) { echo "<li>" . $field_labels[$field] . "</li>"; } 
                    } ?> 
                </ul></div><?php 
            break; 
        case "email_invalid": 
            ?><div class="error">The email address entered does not appear to be a valid format</div><?php 
            break; 
        case "attachment_failed": 
            ?><div class="error">The attachment upload failed.  Perhaps the file is too large?</div><?php 
            break; 
        case "runtime_error": 
            ?><div class="error">There was a problem processing your request.  Please try again later.</div><?php 
            break; 
    } 
} 

?> 
<form action="mail_handler.php" method="post" enctype="multipart/form-data"> 
    <div class="row"> 
        <div class="label">Your name*:</div> 
        <div class="field"><input type="text" name="user_name" value="<?php paint_value("user_name"); ?>" /></div> 
    </div> 
    <div class="row"> 
        <div class="label">Your e-mail*:</div> 
        <div class="field"><input type="text" name="email" value="<?php paint_value("email"); ?>" /></div> 
    </div> 
    <div class="row"> 
        <div class="label">Subject*:</div> 
        <div class="field"><input type="text" name="subject" value="<?php paint_value("subject"); ?>" /></div> 
    </div> 
    <div class="row"> 
        <div class="label">Attachment:</div> 
        <div class="field"><input type="file" name="attachment" /></div> 
    </div> 
    <div class="row"> 
        <div class="label">Comments*:</div> 
        <div class="field"><textarea name="comments"><?php paint_value("comments"); ?></textarea></div> 
    </div> 
    <div class="row"> 
        <div class="label">&nbsp;</div> 
        <div class="field"><input type="submit" name="submit" value="Send" /> 
    </div> 
</form>
This works, I have tested it. End your files with a blank new line by the way.

EDIT | Also fixed the check for if a file was uploaded to check for non-empty tmp_name.

You can download it here to save copy & pasting. Note that the file was written on a Mac so the line ending is \n and some windows editors won't display it correctly.

http://www.w3style.co.uk/~d11wtq/swifttest.zip 51Kb
JeffBell
Forum Newbie
Posts: 15
Joined: Thu Feb 01, 2007 8:17 am

Post by JeffBell »

I can see now that I fat-fingered the disappearing } bracket. Your original code was just fine. Strictly my doing and I've removed those comments.

I did correct the enctype= earlier, but thanks for covering it just in case.

I set up a successful test! 8) I can get the email sent with the attachment on it. One small problem, I was attaching a PDF and it arrived at full size (78K) but it was blank. The original file is definitely not blank.

Any ideas on where I went wrong? I did close the php tag on mail_handler, but I now see you say to leave it open. Could that be the reason the attachment was corrupted? Or is it because the mime type was not set, as talked about here?
http://www.swiftmailer.org/docs/composi ... attachment

Also, my first attachment returned a "too big" error. I didn't see any notation on the Swift Mailer site about sizes; what is the limit? Is that configurable? Just curious. I don't need 800mb attachment limits, but it would be nice to how it's set up.

Thanks again!
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

JeffBell wrote:I can see now that I fat-fingered the disappearing } bracket. Your original code was just fine. Strictly my doing and I've removed those comments.

I did correct the enctype= earlier, but thanks for covering it just in case.

I set up a successful test! 8) I can get the email sent with the attachment on it. One small problem, I was attaching a PDF and it arrived at full size (78K) but it was blank. The original file is definitely not blank.

Any ideas on where I went wrong? I did close the php tag on mail_handler, but I now see you say to leave it open. Could that be the reason the attachment was corrupted? Or is it because the mime type was not set, as talked about here?
http://www.swiftmailer.org/docs/composi ... attachment

Also, my first attachment returned a "too big" error. I didn't see any notation on the Swift Mailer site about sizes; what is the limit? Is that configurable? Just curious. I don't need 800mb attachment limits, but it would be nice to how it's set up.

Thanks again!
The "too" big error is just the error I display if there's a problem with the upload. It "suggests" that the file may have been too large purely because that's the most common error. I'm afraid I won't be taking time to explain how you determine the actual error but basically, if you search php.net for file uploads you'll come across the integer values contains in $_FILES["fieldname"]["error"]. There is no "maximum" upload size set by Swift. PHP has a max memory limit of 8MB and a max upload of 2MB. Even if the attachment is not uploaded you won't get more than about 3MB before exhausting the 8MB limit of the script because there's some caching and encoding going on.

The logic was wrong in the first example before I made the edit above after I posted since I was looking for empty ($_FILES["fieldname"]) rather than checking if there was actually a temporary file uploaded.

For the attachment issue, I suspect I may have stripped slashes from it where I didn't need to. Does removing the following line fix it?

Code: Select all

$attachment_str = stripslashes($attachment_str);
JeffBell
Forum Newbie
Posts: 15
Joined: Thu Feb 01, 2007 8:17 am

Post by JeffBell »

I've been meaning to try this earlier today, but only now got the time. I commented out that line and, yes, the attachments arrive unharmed now.

I will check my example code against the last version you posted above and compare for any differences. And then I'll look into this subject of stripslashes and the issue of forcedownload versus octetstream mime types.

After that, I'll be off creating the forms and functions I want. If I have new questions, I'll write in either a new thread or an existing one (if its on topic).

But, you've essentially provided an excellent tutorial right here which really gets a newbie/non-programmer up and running!

Thank you very much for your effort.

I noticed that you seem to be the main developer of Swift Mailer, actually. (I guess I stumbled into the right place to ask!) I will become a modest donor, for sure, and will make sure it includes a note to reference this discussion so that you know.

EDIT

I was just looking up the tmp_name issue and I found it's a matter of security, apparently.
http://shiflett.org/articles/file-uploads

There, that author suggests using an extra 'if' to verify the attachment is the same as what was uploaded (how that could not be true is something I do not understand). I had been thinking to try to implement that, but it turned out very complicated for me to try integrating it. Nonetheless, I'll leave the link for others.

Also, at the same site, the guy suggests a possible way to check file size. Frankly, I'm not too sure I understand what would happen (in terms of what the user would see) if that code were used and the attachment was deemed too big. But, I was just noting it here for future reference because it seems to address the issue on some level or other.
Last edited by JeffBell on Fri Feb 02, 2007 9:15 am, edited 2 times in total.
Post Reply