Hi everybody,
As anyone who has worked with Couch would know, it uses <cms:send_mail> tag to, ahem, send mails.
This tag internally piggybacks upon PHP mail() function. It is a relatively fast method and needs no configuration but has a couple of drawbacks -
1. Certain hosts choose to disable the mail() functions (security reason, they say).
2. It does not support adding attachments to emails.
To handle the first limitation, we released an addon sometime back that uses the very popular PHPMailer library to send mails (viewtopic.php?p=22911#p22911). As an alternative to the conventional PHP mail() method, this addon could use the SMTP method for delivering mails and that is what we can fall back upon when mail() is disabled on hosts.
However, it did not address the problem of attachments.
You can find a couple of posts on the forum that try to work around this limitation (e.g. viewtopic.php?p=17060#p17060).
However, they all feel (and actually are) pretty hacky to say the least.
With the demand for attachments in emails increasing, we have now extended the PHPMailer addon to include the missing feature.
Also, considering how often we are now beginning to run across hosts that choose to disable the PHP mail() function, we have decided to include the new PHPMailer addon in Couch's core.
As of the publish-date of this post, you won't find the addon in the official Couch installation zip that is available for download from our site.
However, you can get the version of Couch that is available at GitHub (https://github.com/CouchCMS/CouchCMS) and it has the addon included. When the next version of Couch releases, the addon will automatically get included in the downloadable zip on our site. For now, please get it from GitHub.
This post is meant to serve as a little tutorial on using the PHPMailer addon to its full and also as a documentation of the new tags it brings along.
OK, so assuming you have downloaded Couch from GitHub and have installed it, let us begin.
Installation and configuration:
As stated above, this addon comes pre-installed with Couch so nothing needs to be done about it.
However, it does not come enabled by default.
To enable it, please edit your 'couch/config.php' file, find the following directive and set it to '1' -
[
If you are familiar with using other addons in Couch, you might be wondering why we are not using the conventional method of making an entry in 'couch/addons/kfunctions.php' to enable this addon? That method will work too. So, if you so choose, you may place the following line in the mentioned kfunctions.php file and it will work just the same -
The reason for mentioning the first method is backward compatibility. Couch, from its very first version, has shipped with an alternative email script. The original one has now been removed and PHPMailer takes its place.
]
Once you enable this addon, all your existing code using <cms:send_mail> (and also $FUNCS->send_mail() internally) will silently and transparently switchover to using the PHPMailer library.
So, if your original <cms:send_mail> code was working fine, it should continue the same way even after this switchover.
You'll now, however, be able to use attachments in the same <cms:send_mail> code, courtesy PHPMailer now being in the background.
If, however, your original <cms:send_mail> code was not working (owing to PHP mail() function being disabled), switching over to PHPMailer will *not* rectify the problem automatically. Reason being that PHPMailer itself uses the same mail() function as its default way of sending mails.
To rectify the problem, we'll need to instruct PHPMailer to use SMTP as its mail sending method.
To do so, find the file named 'config.example.php' within 'couch/addons/phpmailer' folder and rename it to simply 'config.php'.
Next, open it up in your favorite text editor and find the following lines -
By default, the info you see set in the top four lines has already configured the addon to use Gmail's SMTP server.
Place your Gmail account's username and password in the last two lines and things should be ready to roll.
You are, of course, free to use whichever SMTP server you have at your disposal. Your web-host should be able to provide with all the required info that needs to be entered in the first four lines of config above.
For testing purposes, particularly when the site is still in development stage and is yet on localhost, I personally find the service provided by https://mailtrap.io/ very useful indeed. It is a 'fake' SMTP server that will 'trap' any emails you direct at it and then show it to you in full detail.
Their free tier is more than sufficient for all testing purposes. If it interests you, you can find more info at https://mailtrap.io/blog/2015-05-30-int ... o-mailtrap
My config file looks something like this after entering the creds obtained from mailtrap.io -
A useful tip:
Debugging email problems is always a pain.
One advantage of using PHPMailer is that it is very good at reporting errors and this can be a great help in such situations.
Either set the $cfg['debug'] in the config file being edited to '1' or set the 'debug' parameter of <cms:send_mail> in your code to '1' and you should find a file named 'log.txt' in your site's root containing verbose information about how PHPMailer is trying to push the mail across.
It will also contain info about whether or not it succeeded in doing so. More importantly, in cases of failure, you'll find clear reasons about why it failed. This feature alone is worth switching over to PHPMailer.
Some sample output -
IMP: Do remember to turn off the debug setting once you are done troubleshooting all issues.
Moving on..
so if the only reason why you enabled this addon was to send emails using a SMTP server, you know all that is to be known and you may stop reading at this point.
If, however, you are interested in exploring the new 'attachments' feature, read on
Attachments:
As you'll find yourself as you go through the rest of this tutorial, when it comes to attachments, this addon tries to expose the full functionality of PHPMailer as regular Couch tags.
You'll find no less than three different kinds of attachments being described in full detail below but before we dive into details of each, it would be helpful to take a 10,000 feet overview of them.
Point to keep in mind is that the key reason differentiating the three kind of attachments from one another is the 'source' used to create them.
Broadly speaking, there are three such different sources (and hence three different kind of attachments) -
1. A file uploaded by some visitor using a form on the website
2. A file already existing on the site (e.g. an image in 'images' folder')
3. Output from another script or program e.g. a PDF creator.
If you keep the 'sources' listed above in mind, you'll find it very easy to understand the three types of attachments.
Let us begin with the first one -
1. Uploaded file attachments:
To demonstrate the process of sending mails with attachments created using uploaded files, we'll use the following sample form -
As you can see, the form is a pretty standard one used in Couch but a couple of points need to be stressed upfront -
1. Please notice the use of method="POST" and enctype="multipart/form-data" with the form declaration.
This is essential since we intend to upload files using this form. Forgetting to do so will result in the attachment files failing to upload and you having to spend some time trying to figure out why that is happening.
2. Also notice that I have used hard-coded email addresses for both 'from' and the 'to' parameters of <cms:send_mail> tag.
These addresses should always belong to the same domain as the page hosting the form (mysite.com in our example).
Failing to do so is very likely to result in your hosting provider refusing to relay the mail as most have the policy of only handling mails from the local domain.
It is very tempting to use the email address submitted by the visitor as the 'from' parameter. Please do not do that for the reason explained above.
Instead, use that submitted address as the 'reply_to' parameter, as done in our form above. This way, when you reply to the received mail, the mail client (e.g. Gmail) will automatically show the visitor's address in the 'To' box.
OK, so with those caveats aside, let us now move on to make this form also allow uploading a file that would be then added to the email as an attachment. For that, add the following <cms:input> to the form -
The relevant portion of our form code will now become as follows -
A word about the type 'uploadfile' <cms:input> we just used.
It is a new type that makes it debut with this 'phpmailer' addon.
It works almost like the type 'securefile' editable region you might be familiar with if you have used 'data-bound forms' (http://docs.couchcms.com/concepts/datab ... ound-forms).
Like 'securefile', this input subjects the uploaded file to rigorous security checks before accepting it. However, unlike 'securefile', this input does not persist the uploaded file in database. The file remains a temporary one.
Type 'uploadfile' input accepts the following parameters (in addition to the parameters common to all inputs e.g. 'required') to allow you to fine-tune its working
Moving on, with the input added to the form, the visitor can now upload files that fulfill the specified security criteria.
Finally, to attach the uploaded file to the outgoing mail, modify the <cms:send_mail> block in the form to make it as follows -
As you can see, we have added the following line where the 'field' parameter is set to the name of the type 'uploadfile' <cms:input> we used in the form -
The <cms:attachment> is also a new one and we'll see all its parameters as we move ahead with our tutorial.
One point to stress about this tag is that it will work *only within* the <cms:send_mail> block i.e. it is a child tag of <cms:send_mail> tag.
And that is it. If you are using https://mailtrap.io, try submitting the form and you should see the delivered mail containing the attachment as follows -
Inline variation of uploaded file attachments:
You can see from the screenshot above that the attachment appears as an item separate from the message.
If you are sending plain-text mails, as we have been doing so far in our example, this remains the only option.
However, if you are sending HTML mails we can make the attached image appear 'embedded' within the message itself.
Please try the following as the <cms:send_mail> portion of our form -
Submitting the form with an image will now yield something like this -
Explaining the changes made above to create this 'inline' attachment -
1. Please notice that <cms:send_mail> tag has the 'html' parameter set to '1'. Without this, the mail would be sent in plain-text format and the <IMG> tag would be stripped off from it.
2. The <cms:attachment> tag has its 'inline' parameter set to '1'.
3. The <cms:attachment> tag has been used as the 'src' parameter of the HTML <IMG> tag i.e.
<img src="[PLACE <cms:attachment> HERE BETWEEN THE QUOTES]" />
That is all there is about uploaded file attachments.
Let us now move on to the second type.
2. Disk file attachments
In the method described above, we used the file uploaded by the visitor through a form to create the attachment.
In all likelihood, 99% of the time you'll be using only that method.
However, sometimes it becomes necessary to use already existing files on the server as attachments. For example, as when sending out newsletters or promotional mails to clients - the images (and other attachments e.g. PDFs) contained in such emails will already exist on the server at the time of creating the mail.
In a contrived example, to illustrate the process, I'll add a logo to all emails we have been sending through our example form.
Of course, it doesn't make much sense to add a logo to mails directed to ourselves (as in our ongoing example) but it'll help in comparing the two methods at a single place.
Ok, so suppose we have a logo image on our server at 'http://www.oursite.com/images/logo.gif'. The 'http://www.oursite.com/' part of the URL should belong to the same domain as the site we are on so we can equally write the URL as -
<cms:show k_site_link />images/logo.gif
Add the following line to our <cms:send_mail> block -
The resulting code will now become -
As, I am sure, you make out - the difference between this method of attachment and the previous one is in the use of 'file' parameter instead of the 'field' we have been using so far. Please keep in mind that this 'file' parameter expects a full URL of the file to be attached and that URL has to be of the same domain as the site this code is executing from.
Try submitting the form and you should see the logo appear as a separate attachment
Exactly like the previous method, we can also attach the file as inline.
Try the following -
As you can see, the only difference between the two attachments is the 'file' parameter.
The result -
ONE BIG WARNING ABOUT USING THIS METHOD!
Never, ever, set the 'file' parameter in this method using user-submitted data! Period.
For example, don't accept the file-name from visitors using a form and then use that submitted value to set the 'file' parameter.
This method expects the value to be set explicitly in code, as we did in all the examples above.
Unlike the type 'uploadfile' input used in the first method, it makes no attempt to sanitize or check the path of the specified file.
Allowing visitors to set its value may result in leaving your site open to intrusion.
Alright, so with that we can now move on to our third and final method of creating attachments.
3. No file attachments
For my want of a better expression, I have termed this method as 'No File' attachment.
Allow me to explain. Up till now we have seen two methods and both used physical files to create the attachments (the first method used the uploaded file while the second method used an existing file).
Sometimes, however, we need to create mail attachments dynamically where the source cannot be a static file. Consider the following scenarios -
1. Your site has 3000 members and you need to send some document in the form of a PDF attachment to each of them. The attached PDF is unique for each user as it contains data (e.g. name, text etc.) specific to each user. Instead of creating 3000 unique physical PDF files and then attaching the relevant one for each user, a more pragmatic approach would be to use a PDF generating script that accepts user-specific data and dynamically returns a PDF in string form.
We'll now need to create an attachment using this binary string.
2. The outgoing mail has an embedded image showing a pie chart generated dynamically by an image processing script using data from a database.
3. Finally, the email has image attachments that are stored in a MySQL database as base-encoded blobs.
As you can see, instead of files, we have to create attachments in all the examples above using output of another programs as the source.
Let us try out a simple example of how to do that in Couch.
Add the following to our <cms:send_mail> block -
The modified <cms:send_mail> block now becomes -
You can compare the three types of attachments above.
The primary thing that differentiates this last form of attachment from the other two is that in this case we use the <cms:attachment> as a tag-pair (i.e. <cms:attachment> .. </cms:attachment>) as opposed to as a self-closing tag (i.e. <cms:attachment />) in the first two methods.
Everything enclosed between the two tags becomes the attachment.
Second difference is that in this method we have to mandatorily use the 'name' parameter to specify a valid file name complete with its extension (e.g. 'my_document.txt' or 'logo.gif'). This extension should match the type of the enclosed content.
To understand this point, submit the form to see our new attachment. It should appear as follows -
As you can see, the name of the attachment as shown by the email client is what we specified in the 'name' parameter above. If the user chooses to download the attachment, it will get saved by the same name on her machine. Consider what happens if, instead of 'my_document.txt', we (wrongly) specified 'logo.gif' as the name. The mail client will faithfully show the name as 'logo.gif'. When downloaded, the attachment would be saved as the same name but when the user tries to open this 'image', it will show nothing (because, of course, it is not a valid image).
Point is, this method has no idea about what you are attaching. You need to specify a proper file name for this attachment to be converted into a useful file when downloaded finally.
Interestingly, both the previous methods too support the 'name' parameter but it is not mandatory there (obviously because both have actual files to take the name from). If set, the 'name' parameter will override the name of the actual file. Be aware, though, that if you choose to do so, the onus of setting the right extension would lie entirely on you.
Ok, moving ahead ..
The last example attached a file with textual contents.
More often than not though, you'll use this method to attach binary contents e.g. image or a PDF file. The process remains exactly the same i.e. enclose the contents between the opening and closing tags. Usually it would be PHP code outputting the enclosed content e.g. the following code uses PHP to output an image file -
As you can make out, the PHP code could execute any other script e.g. one that outputs a PDF file.
Exactly like the two previous methods, this attachment also has the 'inline' version.
Try the following <cms:send_mail> block -
The two logos above are identical but the second one has PHP code as its source in contrast to the first one which has a physical file.
Aaand that covers all the three kinds of attachments we can use this addon to send mails with!
Before I sign off, one last topic that is very important while sending HTML mails.
Not all email clients support HTML mails. For such cases, HTML mails carry a plain-text version of the HTML message right within them.
Clients that cannot display HTML versions, automatically use the plain-text version.
If you are a user of Gmail, you'd be familiar with seeing a short excerpt of the message listed alongside the 'subject' on each line of email listings shown by it. Curiously, this excerpt is taken from the plain-text version of the message.
By default, Couch will automatically create a plain-text version from the HTML contents and you don't have to do anything for it.
For example, following is the text version of the last mail we sent (mailtrap.io shows it in a separate tab) -
For the rare case where you are not satisfied with the automatically created text version and wish to exert finer control over it, this addon provides a tag to do just that. Please try the following -
As you can see, the new addition to our code is the <cms:alt_body> block.
This is a very simple tag and will add anything enclosed within it as the plain-text version of the mail. It accepts no parameters.
The result -
That brings this tutorial to an end.
Hope you find it (and the addon) useful.
As always, feedback solicited and welcome.
As anyone who has worked with Couch would know, it uses <cms:send_mail> tag to, ahem, send mails.
This tag internally piggybacks upon PHP mail() function. It is a relatively fast method and needs no configuration but has a couple of drawbacks -
1. Certain hosts choose to disable the mail() functions (security reason, they say).
2. It does not support adding attachments to emails.
To handle the first limitation, we released an addon sometime back that uses the very popular PHPMailer library to send mails (viewtopic.php?p=22911#p22911). As an alternative to the conventional PHP mail() method, this addon could use the SMTP method for delivering mails and that is what we can fall back upon when mail() is disabled on hosts.
However, it did not address the problem of attachments.
You can find a couple of posts on the forum that try to work around this limitation (e.g. viewtopic.php?p=17060#p17060).
However, they all feel (and actually are) pretty hacky to say the least.
With the demand for attachments in emails increasing, we have now extended the PHPMailer addon to include the missing feature.
Also, considering how often we are now beginning to run across hosts that choose to disable the PHP mail() function, we have decided to include the new PHPMailer addon in Couch's core.
As of the publish-date of this post, you won't find the addon in the official Couch installation zip that is available for download from our site.
However, you can get the version of Couch that is available at GitHub (https://github.com/CouchCMS/CouchCMS) and it has the addon included. When the next version of Couch releases, the addon will automatically get included in the downloadable zip on our site. For now, please get it from GitHub.
This post is meant to serve as a little tutorial on using the PHPMailer addon to its full and also as a documentation of the new tags it brings along.
OK, so assuming you have downloaded Couch from GitHub and have installed it, let us begin.
Installation and configuration:
As stated above, this addon comes pre-installed with Couch so nothing needs to be done about it.
However, it does not come enabled by default.
To enable it, please edit your 'couch/config.php' file, find the following directive and set it to '1' -
// 15.
// By default the inbuilt php function 'mail()' is used to deliver messages.
// On certain hosts this function might fail due to configuration problems.
// In such cases, set the following to '1' to use an alternative method (phpMailer) to send emails
define( 'K_USE_ALTERNATIVE_MTA', 0 );
[
If you are familiar with using other addons in Couch, you might be wondering why we are not using the conventional method of making an entry in 'couch/addons/kfunctions.php' to enable this addon? That method will work too. So, if you so choose, you may place the following line in the mentioned kfunctions.php file and it will work just the same -
- Code: Select all
require_once( K_COUCH_DIR.'addons/phpmailer/phpmailer.php' );
The reason for mentioning the first method is backward compatibility. Couch, from its very first version, has shipped with an alternative email script. The original one has now been removed and PHPMailer takes its place.
]
Once you enable this addon, all your existing code using <cms:send_mail> (and also $FUNCS->send_mail() internally) will silently and transparently switchover to using the PHPMailer library.
So, if your original <cms:send_mail> code was working fine, it should continue the same way even after this switchover.
You'll now, however, be able to use attachments in the same <cms:send_mail> code, courtesy PHPMailer now being in the background.
If, however, your original <cms:send_mail> code was not working (owing to PHP mail() function being disabled), switching over to PHPMailer will *not* rectify the problem automatically. Reason being that PHPMailer itself uses the same mail() function as its default way of sending mails.
To rectify the problem, we'll need to instruct PHPMailer to use SMTP as its mail sending method.
To do so, find the file named 'config.example.php' within 'couch/addons/phpmailer' folder and rename it to simply 'config.php'.
Next, open it up in your favorite text editor and find the following lines -
- Code: Select all
// 2. SMTP settings: required only if $cfg['method'] above is set to 'smtp'.
$cfg['host'] = 'smtp.gmail.com'; // Address of the SMTP server. If left empty, defaults to 'localhost'.
$cfg['port'] = '587'; // Port of the SMTP server. If left empty, defaults to '25'.
$cfg['secure'] = 'tls'; // encryption to use on the SMTP connection. Valid options are '', 'ssl' or 'tls'.
$cfg['authentication_required'] = '1'; // set this to '0' if your SMTP server does not require authentication
// If 'authentication_required' above is set to '1', the following credentials will be required
$cfg['username'] = 'your_email@gmail.com';
$cfg['password'] = 'your_password';
By default, the info you see set in the top four lines has already configured the addon to use Gmail's SMTP server.
Place your Gmail account's username and password in the last two lines and things should be ready to roll.
You are, of course, free to use whichever SMTP server you have at your disposal. Your web-host should be able to provide with all the required info that needs to be entered in the first four lines of config above.
For testing purposes, particularly when the site is still in development stage and is yet on localhost, I personally find the service provided by https://mailtrap.io/ very useful indeed. It is a 'fake' SMTP server that will 'trap' any emails you direct at it and then show it to you in full detail.
Their free tier is more than sufficient for all testing purposes. If it interests you, you can find more info at https://mailtrap.io/blog/2015-05-30-int ... o-mailtrap
My config file looks something like this after entering the creds obtained from mailtrap.io -
- Code: Select all
// 2. SMTP settings: required only if $cfg['method'] above is set to 'smtp'.
$cfg['host'] = 'smtp.mailtrap.io'; // Address of the SMTP server. If left empty, defaults to 'localhost'.
$cfg['port'] = '2525'; // Port of the SMTP server. If left empty, defaults to '25'.
$cfg['secure'] = ''; // encryption to use on the SMTP connection. Valid options are '', 'ssl' or 'tls'.
$cfg['authentication_required'] = '1'; // set this to '0' if your SMTP server does not require authentication
// If 'authentication_required' is set to '1' above, the following credentials will be required
$cfg['username'] = '7776096c4eafb86c2';
$cfg['password'] = '9a279ad3242ff5';
A useful tip:
Debugging email problems is always a pain.
One advantage of using PHPMailer is that it is very good at reporting errors and this can be a great help in such situations.
Either set the $cfg['debug'] in the config file being edited to '1' or set the 'debug' parameter of <cms:send_mail> in your code to '1' and you should find a file named 'log.txt' in your site's root containing verbose information about how PHPMailer is trying to push the mail across.
It will also contain info about whether or not it succeeded in doing so. More importantly, in cases of failure, you'll find clear reasons about why it failed. This feature alone is worth switching over to PHPMailer.
Some sample output -
- Code: Select all
CLIENT -> SERVER: EHLO localhost
CLIENT -> SERVER: AUTH CRAM-MD5
CLIENT -> SERVER: NTc3OTA5NmM0ZWdcvjg2YzIgMTMwNjdjNGMxOWEwYzFhNmMwZTg2YWQ2ZGJmN2ZlYTA=
CLIENT -> SERVER: MAIL FROM:<joe@gmail.com>
CLIENT -> SERVER: RCPT TO:<user1@example.com>
CLIENT -> SERVER: RCPT TO:<anotheruser1@example.com>
CLIENT -> SERVER: RCPT TO:<user2@example.com>
CLIENT -> SERVER: RCPT TO:<anotheruser2@example.com>
CLIENT -> SERVER: RCPT TO:<you@yoursite.com>
CLIENT -> SERVER: DATA
CLIENT -> SERVER: Date: Mon, 27 Feb 2017 09:30:01 -0500
CLIENT -> SERVER: To: User1 <user1@example.com>, Another User1 <anotheruser1@example.com>
CLIENT -> SERVER: From: Root User <root@localhost>
CLIENT -> SERVER: Cc: User2 <user2@example.com>, Another User2 <anotheruser2@example.com>
CLIENT -> SERVER: Subject: Your order with XYZ.com
CLIENT -> SERVER: Message-ID: <7e79d7bb87de836b50d7d7b6a2f6ac9e@localhost>
CLIENT -> SERVER: X-Mailer: PHPMailer
CLIENT -> SERVER: MIME-Version: 1.0
CLIENT -> SERVER: Content-Type: text/html; charset=utf-8
CLIENT -> SERVER:
CLIENT -> SERVER: Thank you for your order,
CLIENT -> SERVER: Your order has been confirmed and is being processed. Here is the summary:
CLIENT -> SERVER: Item 1
CLIENT -> SERVER: Item 2
..
..
IMP: Do remember to turn off the debug setting once you are done troubleshooting all issues.
Moving on..
so if the only reason why you enabled this addon was to send emails using a SMTP server, you know all that is to be known and you may stop reading at this point.
If, however, you are interested in exploring the new 'attachments' feature, read on
Attachments:
As you'll find yourself as you go through the rest of this tutorial, when it comes to attachments, this addon tries to expose the full functionality of PHPMailer as regular Couch tags.
You'll find no less than three different kinds of attachments being described in full detail below but before we dive into details of each, it would be helpful to take a 10,000 feet overview of them.
Point to keep in mind is that the key reason differentiating the three kind of attachments from one another is the 'source' used to create them.
Broadly speaking, there are three such different sources (and hence three different kind of attachments) -
1. A file uploaded by some visitor using a form on the website
2. A file already existing on the site (e.g. an image in 'images' folder')
3. Output from another script or program e.g. a PDF creator.
If you keep the 'sources' listed above in mind, you'll find it very easy to understand the three types of attachments.
Let us begin with the first one -
1. Uploaded file attachments:
To demonstrate the process of sending mails with attachments created using uploaded files, we'll use the following sample form -
- Code: Select all
<cms:if "<cms:get_flash 'submit_success' />" >
<h1>Thank you for contacting us!</h1>
</cms:if>
<cms:form method="POST" enctype="multipart/form-data" anchor='0'>
<cms:if k_success >
<!-- email submitted data -->
<cms:send_mail from='contact@mysite.com' to='admin@mysite.com' reply_to=frm_email subject='Contact Form Submission'>
The following is an email sent by a visitor to your site:
Name: <cms:show frm_name />,
Email: <cms:show frm_email />,
Message: <cms:show frm_message />
</cms:send_mail>
<!-- and redirect to refresh page -->
<cms:set_flash name='submit_success' value='1' />
<cms:redirect k_page_link />
</cms:if>
<cms:if k_error >
<ul>
<cms:each k_error >
<li><cms:show item /></li>
</cms:each>
</ul>
</cms:if>
Name: <cms:input type='text' name='name' /><br />
Email: <cms:input type='text' name='email' validator='email' required='1' /><br />
Message: <cms:input type='textarea' name='message' /><br />
<input type="submit" value="Submit" name='submit'>
</cms:form>
As you can see, the form is a pretty standard one used in Couch but a couple of points need to be stressed upfront -
1. Please notice the use of method="POST" and enctype="multipart/form-data" with the form declaration.
This is essential since we intend to upload files using this form. Forgetting to do so will result in the attachment files failing to upload and you having to spend some time trying to figure out why that is happening.
2. Also notice that I have used hard-coded email addresses for both 'from' and the 'to' parameters of <cms:send_mail> tag.
These addresses should always belong to the same domain as the page hosting the form (mysite.com in our example).
Failing to do so is very likely to result in your hosting provider refusing to relay the mail as most have the policy of only handling mails from the local domain.
It is very tempting to use the email address submitted by the visitor as the 'from' parameter. Please do not do that for the reason explained above.
Instead, use that submitted address as the 'reply_to' parameter, as done in our form above. This way, when you reply to the received mail, the mail client (e.g. Gmail) will automatically show the visitor's address in the 'To' box.
OK, so with those caveats aside, let us now move on to make this form also allow uploading a file that would be then added to the email as an attachment. For that, add the following <cms:input> to the form -
- Code: Select all
<cms:input type='uploadfile' name='uploaded_img' required='0' allowed_ext='jpeg,jpg,gif,png' max_size='512' />
The relevant portion of our form code will now become as follows -
- Code: Select all
..
..
Name: <cms:input type='text' name='name' /><br />
Email: <cms:input type='text' name='email' validator='email' required='1' /><br />
Message: <cms:input type='textarea' name='message' /><br />
Attach image: <cms:input type='uploadfile' name='uploaded_img' required='0' allowed_ext='jpeg,jpg,gif,png' max_size='512' /><br />
<input type="submit" value="Submit" name='submit'>
A word about the type 'uploadfile' <cms:input> we just used.
It is a new type that makes it debut with this 'phpmailer' addon.
It works almost like the type 'securefile' editable region you might be familiar with if you have used 'data-bound forms' (http://docs.couchcms.com/concepts/datab ... ound-forms).
Like 'securefile', this input subjects the uploaded file to rigorous security checks before accepting it. However, unlike 'securefile', this input does not persist the uploaded file in database. The file remains a temporary one.
Type 'uploadfile' input accepts the following parameters (in addition to the parameters common to all inputs e.g. 'required') to allow you to fine-tune its working
- Code: Select all
allowed_ext /* Allowed file extensions e.g. 'jpeg,jpg,gif,png' or 'pdf, doc, docx' */
max_size /* in KB. Default is '512' */
max_width /* Pixels. Default is '2048' */
max_height /* Pixels. Default is '2048' */
show_submit /* Shows a button that allows file to be uploaded without submitting the entire form. Default is '0' */
submit_caption /* Caption of the button described above. */
delete_caption /* Caption of delete button */
Moving on, with the input added to the form, the visitor can now upload files that fulfill the specified security criteria.
Finally, to attach the uploaded file to the outgoing mail, modify the <cms:send_mail> block in the form to make it as follows -
- Code: Select all
<!-- email submitted data -->
<cms:send_mail from='contact@mysite.com' to='admin@mysite.com' reply_to=frm_email subject='Contact Form Submission'>
The following is an email sent by a visitor to your site:
Name: <cms:show frm_name />,
Email: <cms:show frm_email />,
Message: <cms:show frm_message />
<cms:attachment field='uploaded_img' />
</cms:send_mail>
As you can see, we have added the following line where the 'field' parameter is set to the name of the type 'uploadfile' <cms:input> we used in the form -
- Code: Select all
<cms:attachment field='uploaded_img' />
The <cms:attachment> is also a new one and we'll see all its parameters as we move ahead with our tutorial.
One point to stress about this tag is that it will work *only within* the <cms:send_mail> block i.e. it is a child tag of <cms:send_mail> tag.
And that is it. If you are using https://mailtrap.io, try submitting the form and you should see the delivered mail containing the attachment as follows -
Inline variation of uploaded file attachments:
You can see from the screenshot above that the attachment appears as an item separate from the message.
If you are sending plain-text mails, as we have been doing so far in our example, this remains the only option.
However, if you are sending HTML mails we can make the attached image appear 'embedded' within the message itself.
Please try the following as the <cms:send_mail> portion of our form -
- Code: Select all
<!-- email submitted data -->
<cms:send_mail html='1' from='contact@mysite.com' to='admin@mysite.com' reply_to=frm_email subject='Contact Form Submission'>
The following is an email sent by a visitor to your site:<br>
Name: <cms:show frm_name />,<br>
Email: <cms:show frm_email />,<br>
Message: <cms:show frm_message /><br>
<cms:if frm_uploaded_img >
<img src="<cms:attachment field='uploaded_img' inline='1' />" />
</cms:if>
</cms:send_mail>
Submitting the form with an image will now yield something like this -
Explaining the changes made above to create this 'inline' attachment -
1. Please notice that <cms:send_mail> tag has the 'html' parameter set to '1'. Without this, the mail would be sent in plain-text format and the <IMG> tag would be stripped off from it.
2. The <cms:attachment> tag has its 'inline' parameter set to '1'.
3. The <cms:attachment> tag has been used as the 'src' parameter of the HTML <IMG> tag i.e.
<img src="[PLACE <cms:attachment> HERE BETWEEN THE QUOTES]" />
That is all there is about uploaded file attachments.
Let us now move on to the second type.
2. Disk file attachments
In the method described above, we used the file uploaded by the visitor through a form to create the attachment.
In all likelihood, 99% of the time you'll be using only that method.
However, sometimes it becomes necessary to use already existing files on the server as attachments. For example, as when sending out newsletters or promotional mails to clients - the images (and other attachments e.g. PDFs) contained in such emails will already exist on the server at the time of creating the mail.
In a contrived example, to illustrate the process, I'll add a logo to all emails we have been sending through our example form.
Of course, it doesn't make much sense to add a logo to mails directed to ourselves (as in our ongoing example) but it'll help in comparing the two methods at a single place.
Ok, so suppose we have a logo image on our server at 'http://www.oursite.com/images/logo.gif'. The 'http://www.oursite.com/' part of the URL should belong to the same domain as the site we are on so we can equally write the URL as -
<cms:show k_site_link />images/logo.gif
Add the following line to our <cms:send_mail> block -
- Code: Select all
<cms:attachment file="<cms:show k_site_link />images/logo.gif" />
The resulting code will now become -
- Code: Select all
<!-- email submitted data -->
<cms:send_mail html='1' from='contact@mysite.com' to='admin@mysite.com' reply_to=frm_email subject='Contact Form Submission'>
The following is an email sent by a visitor to your site:<br>
Name: <cms:show frm_name />,<br>
Email: <cms:show frm_email />,<br>
Message: <cms:show frm_message /><br>
<cms:if frm_uploaded_img >
<img src="<cms:attachment field='uploaded_img' inline='1' />" />
</cms:if>
<cms:attachment file="<cms:show k_site_link />images/logo.gif" />
</cms:send_mail>
As, I am sure, you make out - the difference between this method of attachment and the previous one is in the use of 'file' parameter instead of the 'field' we have been using so far. Please keep in mind that this 'file' parameter expects a full URL of the file to be attached and that URL has to be of the same domain as the site this code is executing from.
Try submitting the form and you should see the logo appear as a separate attachment
Exactly like the previous method, we can also attach the file as inline.
Try the following -
- Code: Select all
<!-- email submitted data -->
<cms:send_mail html='1' from='contact@mysite.com' to='admin@mysite.com' reply_to=frm_email subject='Contact Form Submission'>
The following is an email sent by a visitor to your site:<br>
Name: <cms:show frm_name />,<br>
Email: <cms:show frm_email />,<br>
Message: <cms:show frm_message /><br>
<cms:if frm_uploaded_img >
<img src="<cms:attachment field='uploaded_img' inline='1' />" />
</cms:if>
<img src="<cms:attachment file="<cms:show k_site_link />images/logo.gif" inline='1' />" />
</cms:send_mail>
As you can see, the only difference between the two attachments is the 'file' parameter.
The result -
ONE BIG WARNING ABOUT USING THIS METHOD!
Never, ever, set the 'file' parameter in this method using user-submitted data! Period.
For example, don't accept the file-name from visitors using a form and then use that submitted value to set the 'file' parameter.
This method expects the value to be set explicitly in code, as we did in all the examples above.
Unlike the type 'uploadfile' input used in the first method, it makes no attempt to sanitize or check the path of the specified file.
Allowing visitors to set its value may result in leaving your site open to intrusion.
Alright, so with that we can now move on to our third and final method of creating attachments.
3. No file attachments
For my want of a better expression, I have termed this method as 'No File' attachment.
Allow me to explain. Up till now we have seen two methods and both used physical files to create the attachments (the first method used the uploaded file while the second method used an existing file).
Sometimes, however, we need to create mail attachments dynamically where the source cannot be a static file. Consider the following scenarios -
1. Your site has 3000 members and you need to send some document in the form of a PDF attachment to each of them. The attached PDF is unique for each user as it contains data (e.g. name, text etc.) specific to each user. Instead of creating 3000 unique physical PDF files and then attaching the relevant one for each user, a more pragmatic approach would be to use a PDF generating script that accepts user-specific data and dynamically returns a PDF in string form.
We'll now need to create an attachment using this binary string.
2. The outgoing mail has an embedded image showing a pie chart generated dynamically by an image processing script using data from a database.
3. Finally, the email has image attachments that are stored in a MySQL database as base-encoded blobs.
As you can see, instead of files, we have to create attachments in all the examples above using output of another programs as the source.
Let us try out a simple example of how to do that in Couch.
Add the following to our <cms:send_mail> block -
- Code: Select all
<cms:attachment name='my_document.txt'>
Hello <cms:show frm_name />,
This is a dynamically generated text file.
Hope you like it.
Thanks.
</cms:attachment>
The modified <cms:send_mail> block now becomes -
- Code: Select all
<cms:send_mail html='1' from='contact@mysite.com' to='admin@mysite.com' reply_to=frm_email subject='Contact Form Submission'>
The following is an email sent by a visitor to your site:<br>
Name: <cms:show frm_name />,<br>
Email: <cms:show frm_email />,<br>
Message: <cms:show frm_message /><br>
<cms:if frm_uploaded_img >
<img src="<cms:attachment field='uploaded_img' inline='1' />" />
</cms:if>
<img src="<cms:attachment file="<cms:show k_site_link />images/logo.gif" inline='1' />" />
<cms:attachment name='my_document.txt'>
Hello <cms:show frm_name />,
This is a dynamically generated text file.
Hope you like it.
Thanks.
</cms:attachment>
</cms:send_mail>
You can compare the three types of attachments above.
The primary thing that differentiates this last form of attachment from the other two is that in this case we use the <cms:attachment> as a tag-pair (i.e. <cms:attachment> .. </cms:attachment>) as opposed to as a self-closing tag (i.e. <cms:attachment />) in the first two methods.
Everything enclosed between the two tags becomes the attachment.
Second difference is that in this method we have to mandatorily use the 'name' parameter to specify a valid file name complete with its extension (e.g. 'my_document.txt' or 'logo.gif'). This extension should match the type of the enclosed content.
To understand this point, submit the form to see our new attachment. It should appear as follows -
As you can see, the name of the attachment as shown by the email client is what we specified in the 'name' parameter above. If the user chooses to download the attachment, it will get saved by the same name on her machine. Consider what happens if, instead of 'my_document.txt', we (wrongly) specified 'logo.gif' as the name. The mail client will faithfully show the name as 'logo.gif'. When downloaded, the attachment would be saved as the same name but when the user tries to open this 'image', it will show nothing (because, of course, it is not a valid image).
Point is, this method has no idea about what you are attaching. You need to specify a proper file name for this attachment to be converted into a useful file when downloaded finally.
Interestingly, both the previous methods too support the 'name' parameter but it is not mandatory there (obviously because both have actual files to take the name from). If set, the 'name' parameter will override the name of the actual file. Be aware, though, that if you choose to do so, the onus of setting the right extension would lie entirely on you.
Ok, moving ahead ..
The last example attached a file with textual contents.
More often than not though, you'll use this method to attach binary contents e.g. image or a PDF file. The process remains exactly the same i.e. enclose the contents between the opening and closing tags. Usually it would be PHP code outputting the enclosed content e.g. the following code uses PHP to output an image file -
- Code: Select all
<cms:attachment name='logo.gif'>
<cms:php>echo file_get_contents('<cms:show k_site_path />images/logo.gif');</cms:php>
</cms:attachment>
As you can make out, the PHP code could execute any other script e.g. one that outputs a PDF file.
Exactly like the two previous methods, this attachment also has the 'inline' version.
Try the following <cms:send_mail> block -
- Code: Select all
<cms:send_mail html='1' from='contact@mysite.com' to='admin@mysite.com' reply_to=frm_email subject='Contact Form Submission'>
The following is an email sent by a visitor to your site:<br>
Name: <cms:show frm_name />,<br>
Email: <cms:show frm_email />,<br>
Message: <cms:show frm_message /><br>
<cms:if frm_uploaded_img >
<img src="<cms:attachment field='uploaded_img' inline='1' />" />
</cms:if>
<img src="<cms:attachment file="<cms:show k_site_link />images/logo.gif" inline='1' />" />
<cms:capture into='my_binary_img'>
<cms:php>echo file_get_contents('<cms:show k_site_path />images/logo.gif');</cms:php>
</cms:capture>
<img src="<cms:attachment name='logo.gif' inline='1'><cms:show my_binary_img /></cms:attachment>">
</cms:send_mail>
The two logos above are identical but the second one has PHP code as its source in contrast to the first one which has a physical file.
Aaand that covers all the three kinds of attachments we can use this addon to send mails with!
Before I sign off, one last topic that is very important while sending HTML mails.
Not all email clients support HTML mails. For such cases, HTML mails carry a plain-text version of the HTML message right within them.
Clients that cannot display HTML versions, automatically use the plain-text version.
If you are a user of Gmail, you'd be familiar with seeing a short excerpt of the message listed alongside the 'subject' on each line of email listings shown by it. Curiously, this excerpt is taken from the plain-text version of the message.
By default, Couch will automatically create a plain-text version from the HTML contents and you don't have to do anything for it.
For example, following is the text version of the last mail we sent (mailtrap.io shows it in a separate tab) -
For the rare case where you are not satisfied with the automatically created text version and wish to exert finer control over it, this addon provides a tag to do just that. Please try the following -
- Code: Select all
<cms:send_mail html='1' from='contact@mysite.com' to='admin@mysite.com' reply_to=frm_email subject='Contact Form Submission'>
The following is an email sent by a visitor to your site:<br>
Name: <cms:show frm_name />,<br>
Email: <cms:show frm_email />,<br>
Message: <cms:show frm_message /><br>
<cms:if frm_uploaded_img >
<img src="<cms:attachment field='uploaded_img' inline='1' />" />
</cms:if>
<img src="<cms:attachment file="<cms:show k_site_link />images/logo.gif" inline='1' />" />
<cms:capture into='my_binary_img'>
<cms:php>echo file_get_contents('<cms:show k_site_path />images/logo.gif');</cms:php>
</cms:capture>
<img src="<cms:attachment name='logo.gif' inline='1'><cms:show my_binary_img /></cms:attachment>">
<cms:alt_body>
Hello!
Since you do not seem to be a person who is easily satisfied, here is a manually created plain text version of this mail -
<cms:repeat '3'>
Line <cms:show k_count />.
</cms:repeat>
Hope you like it.
</cms:alt_body>
</cms:send_mail>
As you can see, the new addition to our code is the <cms:alt_body> block.
This is a very simple tag and will add anything enclosed within it as the plain-text version of the mail. It accepts no parameters.
The result -
That brings this tutorial to an end.
Hope you find it (and the addon) useful.
As always, feedback solicited and welcome.