<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.moodle.org/test/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Matm</id>
	<title>MoodleDocs - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.moodle.org/test/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Matm"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/Special:Contributions/Matm"/>
	<updated>2026-04-18T02:59:04Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=33685</id>
		<title>Email processing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=33685"/>
		<updated>2008-03-17T09:02:56Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* Email confirmation or registration words, and how to edit them. */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Features ==&lt;br /&gt;
&lt;br /&gt;
Moodle now makes better use of the SMTP protocol and email in general. Most of the benefits result from using a technique known as Variable Envelope Return Path (VERP).&lt;br /&gt;
&lt;br /&gt;
* Works on most modern MTAs (at least on Unix systems).&lt;br /&gt;
* All processing of bounces and replies is secured using HMAC-MD5-8.&lt;br /&gt;
* Bounces are handled correctly and increase a &amp;quot;bad email&amp;quot; score for the user.&lt;br /&gt;
* noreply@host address is now on Reply-to field, avoiding accidental pollution of users address books.&lt;br /&gt;
* noreply@host has an autorresponder&lt;br /&gt;
* Makes it easy for modules to send emails with a signed VERP reply-to.&lt;br /&gt;
* Handles receving of VERP replies: Validates the HMAC-MD5-8 signature and Dispatches the encoded request data to the relevant module&lt;br /&gt;
&lt;br /&gt;
== Moodle configuration ==&lt;br /&gt;
&lt;br /&gt;
Edit config.php to enable bounce handling, and setup Moodle to match your MTA configuration. Here&#039;s how. Uncomment these lines in config.php (if you cannot find them, copy them from config-dist.php):&lt;br /&gt;
&lt;br /&gt;
  // once handlebounces is true, we will be using VERP for the return address of every sent email&lt;br /&gt;
  $CFG-&amp;gt;handlebounces = true;&lt;br /&gt;
  // minimum bounces allowed per user&lt;br /&gt;
  $CFG-&amp;gt;minbounces = 10;&lt;br /&gt;
  // ratio of bad emails to sent emails&lt;br /&gt;
  // if we get more than 20% bounces &lt;br /&gt;
  // for a given user, his/her email is marked bad&lt;br /&gt;
  $CFG-&amp;gt;bounceratio = .20;&lt;br /&gt;
&lt;br /&gt;
Edit the $CFG-&amp;gt;maildomain line and one of the $CFG-&amp;gt;mailprefix lines (the one that matches your MTA).&lt;br /&gt;
&lt;br /&gt;
Make sure your server has a command-line PHP interpreter, and that it is able to connect to mysql (or postgres if relevant). If you are able to run cron.php from the commandline or from crontab, this means PHP is ok.&lt;br /&gt;
&lt;br /&gt;
Edit the process_email.php script to point to the location of your php binary. It will usually be &#039;&#039;/usr/bin/php&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Email confirmation or registration words, and how to edit them.==&lt;br /&gt;
*  Students receive a confirmation email when they create a user account.  This text can be found in the lang/?/moodle.php as the emailconfirmation &amp;quot;variable&amp;quot;.&lt;br /&gt;
* Students receive a welcome email when they enroll in a course.  This text can be found in the lang/?/moodle.php file as the welcometocoursetext &amp;quot;variable&amp;quot;.&lt;br /&gt;
*If you feel the need to edit this text, the best way to do this is to go to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit. Once you have done this, hit the &amp;quot;Switch lang directory&amp;quot; button, and do your editing.&lt;br /&gt;
*If you decide to get your hands dirty and work by editing the moodle.php directly, be careful to open the file only in a simple text editor like notepad or wordpad. &lt;br /&gt;
*Tip: Be careful with markup - as you edit, you must use &amp;quot; &amp;quot; for things like putting in hyperlinks, titles and targets. You MUST &#039;escape&#039; them by putting a \ before each &amp;quot;. If you don&#039;t the resulting page will appear blank. For example, the normal way to markup a hyperlink is:-&lt;br /&gt;
**&amp;lt;nowiki&amp;gt;&amp;lt;a href=&amp;quot;http://www.blah_blah&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt; If you do this in the moodle.php file, your edited text won&#039;t appear.&lt;br /&gt;
**Use &amp;lt;nowiki&amp;gt;&amp;lt;a href=\&amp;quot;http://www.blah_blah\&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
*Use the \ before each &amp;quot; when marking up things like target=\&amp;quot;_blank\&amp;quot; and title=\&amp;quot;Blah blah\&amp;quot; and other similar codes.&lt;br /&gt;
*If you feel you must really go the route of editing the moodle.php file directly, save a copy of the file in its own folder (copy and paste the file in the same folder). That way, if it all goes wrong for you, all you have to do is delete the botched file and rename the &#039;copy of moodle.php&#039; back to &#039;moodle.php&#039; and you are back to square one, no harm done!&lt;br /&gt;
*Having said all that, it is best to do all your editing in the web interface by going to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit.&lt;br /&gt;
[[Image:Example.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Setup under Postfix ==&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;|&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; and moodle installed under /var/www/moodle we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
== Setup under Qmail ==&lt;br /&gt;
&lt;br /&gt;
Depending on your setup, your aliases will be controlled by one or more of&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;/etc/aliases&#039;&#039;&lt;br /&gt;
* &#039;&#039;/var/qmail/alias/.qmail-PREFIX&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you edit /etc/aliases add a line like this (for a prefix of &#039;mdl&#039;):&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you create /var/qmail/alias/.qmail-PREFIX, just do&lt;br /&gt;
&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-mdl&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-noreply&lt;br /&gt;
&lt;br /&gt;
To this three letter prefix, we will add a &#039;-&#039; when sending and receiving messages. For more info, check out the manpage for dot-qmail.&lt;br /&gt;
&lt;br /&gt;
== Setup under Exim ==&lt;br /&gt;
&lt;br /&gt;
Open &#039;&#039;/etc/exim/exim.conf&#039;&#039; and add to trusted_users the user Apache and cron.php run as (usually &amp;quot;www-data&amp;quot; or &amp;quot;nobody&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;+&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
More documentation about Exim can be found [http://www.exim.org/docs.html here]. You may have to tell Exim not to lowercase the local-part.&lt;br /&gt;
&lt;br /&gt;
== Developer info ==&lt;br /&gt;
&lt;br /&gt;
Changed functions:&lt;br /&gt;
&lt;br /&gt;
* email_to_user() will set the envelope sender to a special bounce processing address (based on $CFG settings)&lt;br /&gt;
* email_to_user() will accept (and set) a reply-to header, to be generated by the module calling the function.&lt;br /&gt;
* associated string changes/additions&lt;br /&gt;
&lt;br /&gt;
New functions:&lt;br /&gt;
&lt;br /&gt;
* generate_email_processing_address() - ALWAYS use this to generate the reply-to header. reply-to header will look like this: (LIMIT: 64 chars total) prefix - EXACTLY four chars encodeded, packed, moduleid (0 for core) (2 chars) up to 42 chars for the modules to put anything they want it (can contain userid (or, eg for forum, postids to reply to), or anything really. 42 chars is ABSOLUTE LIMIT) 16 char hash (half an md5) of the first part of the address, together with a site &amp;quot;secret&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* moodle_process_email() - any non-module email processing goes here (currently used for processing bounces)&lt;br /&gt;
&lt;br /&gt;
New files:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/process_email.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This script needs to be called from your MTA for anything starting with the 3 char prefix described above (and optionally, the noreply address).&lt;br /&gt;
&lt;br /&gt;
How does it work? It will break down and unencode the email address into moduleid and validate the half md5 hash, and call $modname_process_email (if it exists). Arguments to these functions are: $modargs (any part of the email address that isn&#039;t the prefix, modid or the hash) and the contents of the email (read from STDIN).&lt;br /&gt;
&lt;br /&gt;
It doubles up as the noreplyaddress autorresponder if you configure it with that address as well. Replying with a friendly &amp;quot;this is not a real email address&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
== Module Authors ==&lt;br /&gt;
&lt;br /&gt;
Take a look at new functions moodle_process_email() and generate_email_processing_address() in moodlelib.php for ideas about how to&lt;br /&gt;
&lt;br /&gt;
* encode and unencode the arguments your module needs to do the processing&lt;br /&gt;
* how to deal with multiple &amp;quot;actions&amp;quot; for any given module.&lt;br /&gt;
&lt;br /&gt;
In a nutshell, users can send emails to Moodle using special dynamic addresses. These emails can trigger a call to a module function in the form of modulename_process_email($str, $bodyofemail). The $str part will be up to 42 characters of data generated by Moodle (presumably by your own module), and the $bodyofemailpart is the contents of the email (got by reading STDIN - usually generated by the users MUA).&lt;br /&gt;
&lt;br /&gt;
The 42 characters come from the &amp;quot;local part&amp;quot; of an email address (the part before the @ sign) which can have up to 64 chars. Out of those 64 chars, Moodle uses 22 characters, leaving you with 42 characters to encode data.&lt;br /&gt;
&lt;br /&gt;
What do we do with the 22 chars? Four go to the prefix, which we need to let the MTA know to pass the message to our script. Two go to identify the module ID so we know which module has generated the message (and so we dispatch the request to that module). The remaining 16 are a signature (HMAC-MD5-8) we use to authenticate the message.&lt;br /&gt;
&lt;br /&gt;
Forty-two characters isn&#039;t a lot (although it could be the answer to life, the universe, and everything!) so make sure you use those characters wisely.&lt;br /&gt;
&lt;br /&gt;
The most efficient way to encode database IDs in their full range (so that they can be placed in an email address) we have found is base64_encode(pack(&#039;V&#039;,2147483647)), which returns &amp;quot;/ / / / f w = =&amp;quot;. The two trailing &amp;quot;= =&amp;quot; are redundant and you can remove them (you&#039;ll need to reappend them when retrieving your data). Join your parameters as encoded IDs in positional slots for efficiency.&lt;br /&gt;
&lt;br /&gt;
To retrieve your data, use substr() to separate your parameters, and then unpack(&#039;V&#039;,base64_decode($str)). Note that it&#039;ll return a one-element array.&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Using &#039;V&#039; reaches 2147483647, half the range of mySQL&#039;s INT. Additionally, &#039;V&#039; behaves like a signed value, rather than an unsigned, so I suspect there&#039;s a bug in PHP&#039;s documentation of pack().&lt;br /&gt;
&lt;br /&gt;
With each ID taking 6-chars (8 chars if we find a way to use the full range of &#039;V&#039;), you have a limited number of parameters. If you need to encode more information, store it in the DB and send emails that point to your stored data. Remember to cleanup this temporary data after a safe period of time.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Do not try to use variable-width encoding to put IDs, as it&#039;ll work in small installations and break in larger ones.&lt;br /&gt;
&lt;br /&gt;
== Security issues ==&lt;br /&gt;
&lt;br /&gt;
Any code in modulename_process_email() _must_ assume it will see repeat replies and handle them gracefully. The definition of &#039;gracefully&#039; depends on what the code does.&lt;br /&gt;
&lt;br /&gt;
Email servers (MTAs) will sometimes re-transmit a message if they are unsure that the receiving MTA got it -- and sysadmins may sometimes replay a whole email queue if something&#039;s gone wrong. In that case, they email body will be identical, the headers slightly different.&lt;br /&gt;
&lt;br /&gt;
In a different case, the user may &#039;reply&#039; to the message twice. Perhaps in error, perhaps purposefully. What to do depends on the specific scenario.&lt;br /&gt;
&lt;br /&gt;
We /could/ support better protection at the framework level, by keeping track of every reply-to address we send out. We decided against that because (a) the performance impact will be important (b) we want the 1st cut to be lightweight and simple to change in case we need to.&lt;br /&gt;
&lt;br /&gt;
With this the initial implementation, modules should expose functions that handle these &amp;quot;replay&amp;quot; cases correctly. If later we want to expose additional functions, we can add such tracking as an optional thing. It&#039;d be awful to have it across all emails sent from Moodle.&lt;br /&gt;
&lt;br /&gt;
== Experimental email processing, pending merge into 1.9/2.0 ==&lt;br /&gt;
===Module Authors===&lt;br /&gt;
The email interface allows you to let users respond to emails sent via your module and affect change in them. The basic idea is that each email is uniquely identified with an email session that carries with it a simple payload. This payload is stored via database, and cannot be changed by the user. Replies are handled by module code in your lib.php library - modulename_process_email($payload, $body) - which is passed the session payload and the body (with full headers) of the email received, to be parsed as you like. Some utility functions are available as well to help with this.&lt;br /&gt;
&lt;br /&gt;
Here is an outline of the intended use:&lt;br /&gt;
* Before sending an email to a user via the email_to_user() function, the module should check to see if the config variable $CFG-&amp;gt;emailinterface is enabled. (This is off by default)&lt;br /&gt;
* Assuming the email interface is enabled, the function generate_email_verp_address($moduleid, $payload, $userid) should be called to create an &amp;quot;email session&amp;quot;. The payload should include any data you wish to use in your handling routine - such as the id of the user, or what part of the interface he is interacting with. The function will return a string containing the email session id.&lt;br /&gt;
* Call the email_to_user() function as normal, appending the email session id as the 11th parameter. Keep in mind that you will probably also need to change the text or html of the email to point out that the email interface is active.&lt;br /&gt;
* A function contained in the lib.php file of your module, named [modulename]_process_email($payload, $body) should be written. This is the handler function, which is called when an email reply is received. This function can inspect the contents of the payload received, then parse the email body for data. The $body parameter returns the full email, including the headers.&lt;br /&gt;
&lt;br /&gt;
Note that each email can only be replied to once - the email session is destroyed once an email has been received. If you wish to have multiple replies from a user, you will have to create a new session (and new email) every time. The email session table is also regularly pruned, the default settings allow sessions to persist for one month.&lt;br /&gt;
&lt;br /&gt;
The following utility functions are also defined in admin/process_email.php, which can help:&lt;br /&gt;
* get_email_subject($fullemail) - return the subject of an email&lt;br /&gt;
* strip_email_headers($fullemail) - strip all headers off an email&lt;br /&gt;
* email_is_multipart($fullemail) - determine if an email is a multipart message&lt;br /&gt;
* seperate_multipart($multipartmsg) - seperate a multipart email message into an array of parts, each of which has headers and a body.&lt;br /&gt;
* get_multipart_content_type($part) - determine the content-type of a multipart, generally text/plain or text/html.&lt;br /&gt;
* multipart_is_quoted_printable($part) - determine if a email part has been encoded with the quoted-printable encoding - some email clients tend to do this to html.&lt;br /&gt;
* decode_quoted_printable($partdata) - decode a email that has been encoded with quoted-printable encoding - this needs to be run on the data section of a part (strip_email_headers can be used to seperate the headers of a part).&lt;br /&gt;
* strip_email_reply($body, $ishtml, $identifier) - strip all irrelevant lines of an email message based on a unique identifier embedded within the original message. This is used to determine what is user input, and what is irrelevant data the email client has added.&lt;br /&gt;
* strip_email_reply_multi($body, $ishtml, $identifier) - as above, but allowing for multiple sections of possible user input in a single email message.&lt;br /&gt;
&lt;br /&gt;
Examples of use of these functions can be seen in the handler for the forum module. The idea behind the strip reply functions is that the original email will contain a unique identifier, such as a random 10 character string. This is embedded in a line with instructions for the user to write below and above it, e.g:&lt;br /&gt;
  \/ Please put your response here [ABCDEFGHIJ] \/&lt;br /&gt;
  &amp;lt;User Data&amp;gt;&lt;br /&gt;
  /\ Please put your response here [ABCDEFGHIJ] /\&lt;br /&gt;
This is necessary because of the wide differences between webmail and email clients in handling quotes and prefixing dates/times to replied emails. Keep in mind that text emails have an 80-character line width restrictions, which must also include the quote added by the email client, so any line of a text-email with this identifier should be kept to at least 77 characters to avoid wrapping by an email client. This unique identifier can be easily stored in the payload. Multiple input sections are handled similarly - a number is appended to the end of the identifier, e.g. [ABCDEFGHIJ1] to signfiy the first section of input. The strip_email_reply_multi returns an array containing a map from each numbered section it finds to a string containing all data in that section.&lt;br /&gt;
&lt;br /&gt;
===Developer Info===&lt;br /&gt;
The reply-to header is now encoded in base32 instead of base64 to allow for case-insensitive MTA&#039;s. Generate_email_processing_address was left as a backwards-compatibility wrapper, modules should use generate_email_verp_address now instead.&lt;br /&gt;
&lt;br /&gt;
Email sessions have been created to deal with the lack of space avaliable in the header under base32, payloads are stored in a new table mdl_email_sessions, and are identified with a unique base32 key which is embedded in the reply-to header. Each row has a timestamp, and the table is pruned during cleanup cron in admin/cron.php.&lt;br /&gt;
&lt;br /&gt;
Bounce detection is now linked in with the email interface - bounce detection is included in admin/process_email.php. Some new configuration variables have also been created to help configure these changes - $CFG-&amp;gt;emailinterface and $CFG-&amp;gt;emailsessiontime - and both have been added to the server settings admin page.&lt;br /&gt;
&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27338</id>
		<title>Email processing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27338"/>
		<updated>2007-09-26T19:42:19Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* Email confirmation or registration words, and how to edit them. */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Features ==&lt;br /&gt;
&lt;br /&gt;
Moodle now makes better use of the SMTP protocol and email in general. Most of the benefits result from using a technique known as Variable Envelope Return Path (VERP).&lt;br /&gt;
&lt;br /&gt;
* Works on most modern MTAs (at least on Unix systems).&lt;br /&gt;
* All processing of bounces and replies is secured using HMAC-MD5-8.&lt;br /&gt;
* Bounces are handled correctly and increase a &amp;quot;bad email&amp;quot; score for the user.&lt;br /&gt;
* noreply@host address is now on Reply-to field, avoiding accidental pollution of users address books.&lt;br /&gt;
* noreply@host has an autorresponder&lt;br /&gt;
* Makes it easy for modules to send emails with a signed VERP reply-to.&lt;br /&gt;
* Handles receving of VERP replies: Validates the HMAC-MD5-8 signature and Dispatches the encoded request data to the relevant module&lt;br /&gt;
&lt;br /&gt;
== Moodle configuration ==&lt;br /&gt;
&lt;br /&gt;
Edit config.php to enable bounce handling, and setup Moodle to match your MTA configuration. Here&#039;s how. Uncomment these lines in config.php (if you cannot find them, copy them from config-dist.php):&lt;br /&gt;
&lt;br /&gt;
  // once handlebounces is true, we will be using VERP for the return address of every sent email&lt;br /&gt;
  $CFG-&amp;gt;handlebounces = true;&lt;br /&gt;
  // minimum bounces allowed per user&lt;br /&gt;
  $CFG-&amp;gt;minbounces = 10;&lt;br /&gt;
  // ratio of bad emails to sent emails&lt;br /&gt;
  // if we get more than 20% bounces &lt;br /&gt;
  // for a given user, his/her email is marked bad&lt;br /&gt;
  $CFG-&amp;gt;bounceratio = .20;&lt;br /&gt;
&lt;br /&gt;
Edit the $CFG-&amp;gt;maildomain line and one of the $CFG-&amp;gt;mailprefix lines (the one that matches your MTA).&lt;br /&gt;
&lt;br /&gt;
Make sure your server has a command-line PHP interpreter, and that it is able to connect to mysql (or postgres if relevant). If you are able to run cron.php from the commandline or from crontab, this means PHP is ok.&lt;br /&gt;
&lt;br /&gt;
Edit the process_email.php script to point to the location of your php binary. It will usually be &#039;&#039;/usr/bin/php&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Email confirmation or registration words, and how to edit them.==&lt;br /&gt;
*  Students receive a confirmation email when they create a user account.  This text can be found in the lang/?/moodle.php as the emailconfirmation &amp;quot;variable&amp;quot;.&lt;br /&gt;
* Students receive a welcome email when they enroll in a course.  This text can be found in the lang/?/moodle.php file as the welcometocoursetext &amp;quot;variable&amp;quot;.&lt;br /&gt;
*If you feel the need to edit this text, the best way to do this is to go to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit. Once you have done this, hit the &amp;quot;Switch lang directory&amp;quot; button, and do your editing.&lt;br /&gt;
*If you decide to get your hands dirty and work by editing the moodle.php directly, be careful to open the file only in a simple text editor like notepad or wordpad. &lt;br /&gt;
*Tip: Be careful with markup - as you edit, you must use &amp;quot; &amp;quot; for things like putting in hyperlinks, titles and targets. You MUST &#039;escape&#039; them by putting a \ before each &amp;quot;. If you don&#039;t the resulting page will appear blank. For example, the normal way to markup a hyperlink is:-&lt;br /&gt;
**&amp;lt;nowiki&amp;gt;&amp;lt;a href=&amp;quot;http://www.blah_blah&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt; If you do this in the moodle.php file, your edited text won&#039;t appear.&lt;br /&gt;
**Use &amp;lt;nowiki&amp;gt;&amp;lt;a href=\&amp;quot;http://www.blah_blah\&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
*Use the \ before each &amp;quot; when marking up things like target=\&amp;quot;_blank&amp;quot; and title=\&amp;quot;Blah blah\&amp;quot; and other similar codes.&lt;br /&gt;
*If you feel you must really go the route of editing the moodle.php file directly, save a copy of the file in its own folder (copy and paste the file in the same folder). That way, if it all goes wrong for you, all you have to do is delete the botched file and rename the &#039;copy of moodle.php&#039; back to &#039;moodle.php&#039; and you are back to square one, no harm done!&lt;br /&gt;
*Having said all that, it is best to do all your editing in the web interface by going to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit.&lt;br /&gt;
[[Image:Example.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Setup under Postfix ==&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;|&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; and moodle installed under /var/www/moodle we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
== Setup under Qmail ==&lt;br /&gt;
&lt;br /&gt;
Depending on your setup, your aliases will be controlled by one or more of&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;/etc/aliases&#039;&#039;&lt;br /&gt;
* &#039;&#039;/var/qmail/alias/.qmail-PREFIX&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you edit /etc/aliases add a line like this (for a prefix of &#039;mdl&#039;):&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you create /var/qmail/alias/.qmail-PREFIX, just do&lt;br /&gt;
&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-mdl&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-noreply&lt;br /&gt;
&lt;br /&gt;
To this three letter prefix, we will add a &#039;-&#039; when sending and receiving messages. For more info, check out the manpage for dot-qmail.&lt;br /&gt;
&lt;br /&gt;
== Setup under Exim ==&lt;br /&gt;
&lt;br /&gt;
Open &#039;&#039;/etc/exim/exim.conf&#039;&#039; and add to trusted_users the user Apache and cron.php run as (usually &amp;quot;www-data&amp;quot; or &amp;quot;nobody&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;+&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
More documentation about Exim can be found [http://www.exim.org/docs.html here]. You may have to tell Exim not to lowercase the local-part.&lt;br /&gt;
&lt;br /&gt;
== Developer info ==&lt;br /&gt;
&lt;br /&gt;
Changed functions:&lt;br /&gt;
&lt;br /&gt;
* email_to_user() will set the envelope sender to a special bounce processing address (based on $CFG settings)&lt;br /&gt;
* email_to_user() will accept (and set) a reply-to header, to be generated by the module calling the function.&lt;br /&gt;
* associated string changes/additions&lt;br /&gt;
&lt;br /&gt;
New functions:&lt;br /&gt;
&lt;br /&gt;
* generate_email_processing_address() - ALWAYS use this to generate the reply-to header. reply-to header will look like this: (LIMIT: 64 chars total) prefix - EXACTLY four chars encodeded, packed, moduleid (0 for core) (2 chars) up to 42 chars for the modules to put anything they want it (can contain userid (or, eg for forum, postids to reply to), or anything really. 42 chars is ABSOLUTE LIMIT) 16 char hash (half an md5) of the first part of the address, together with a site &amp;quot;secret&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* moodle_process_email() - any non-module email processing goes here (currently used for processing bounces)&lt;br /&gt;
&lt;br /&gt;
New files:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/process_email.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This script needs to be called from your MTA for anything starting with the 3 char prefix described above (and optionally, the noreply address).&lt;br /&gt;
&lt;br /&gt;
How does it work? It will break down and unencode the email address into moduleid and validate the half md5 hash, and call $modname_process_email (if it exists). Arguments to these functions are: $modargs (any part of the email address that isn&#039;t the prefix, modid or the hash) and the contents of the email (read from STDIN).&lt;br /&gt;
&lt;br /&gt;
It doubles up as the noreplyaddress autorresponder if you configure it with that address as well. Replying with a friendly &amp;quot;this is not a real email address&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
== Module Authors ==&lt;br /&gt;
&lt;br /&gt;
Take a look at new functions moodle_process_email() and generate_email_processing_address() in moodlelib.php for ideas about how to&lt;br /&gt;
&lt;br /&gt;
* encode and unencode the arguments your module needs to do the processing&lt;br /&gt;
* how to deal with multiple &amp;quot;actions&amp;quot; for any given module.&lt;br /&gt;
&lt;br /&gt;
In a nutshell, users can send emails to Moodle using special dynamic addresses. These emails can trigger a call to a module function in the form of modulename_process_email($str, $bodyofemail). The $str part will be up to 42 characters of data generated by Moodle (presumably by your own module), and the $bodyofemailpart is the contents of the email (got by reading STDIN - usually generated by the users MUA).&lt;br /&gt;
&lt;br /&gt;
The 42 characters come from the &amp;quot;local part&amp;quot; of an email address (the part before the @ sign) which can have up to 64 chars. Out of those 64 chars, Moodle uses 22 characters, leaving you with 42 characters to encode data.&lt;br /&gt;
&lt;br /&gt;
What do we do with the 22 chars? Four go to the prefix, which we need to let the MTA know to pass the message to our script. Two go to identify the module ID so we know which module has generated the message (and so we dispatch the request to that module). The remaining 16 are a signature (HMAC-MD5-8) we use to authenticate the message.&lt;br /&gt;
&lt;br /&gt;
Forty-two characters isn&#039;t a lot (although it could be the answer to life, the universe, and everything!) so make sure you use those characters wisely.&lt;br /&gt;
&lt;br /&gt;
The most efficient way to encode database IDs in their full range (so that they can be placed in an email address) we have found is base64_encode(pack(&#039;V&#039;,2147483647)), which returns &amp;quot;/ / / / f w = =&amp;quot;. The two trailing &amp;quot;= =&amp;quot; are redundant and you can remove them (you&#039;ll need to reappend them when retrieving your data). Join your parameters as encoded IDs in positional slots for efficiency.&lt;br /&gt;
&lt;br /&gt;
To retrieve your data, use substr() to separate your parameters, and then unpack(&#039;V&#039;,base64_decode($str)). Note that it&#039;ll return a one-element array.&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Using &#039;V&#039; reaches 2147483647, half the range of mySQL&#039;s INT. Additionally, &#039;V&#039; behaves like a signed value, rather than an unsigned, so I suspect there&#039;s a bug in PHP&#039;s documentation of pack().&lt;br /&gt;
&lt;br /&gt;
With each ID taking 6-chars (8 chars if we find a way to use the full range of &#039;V&#039;), you have a limited number of parameters. If you need to encode more information, store it in the DB and send emails that point to your stored data. Remember to cleanup this temporary data after a safe period of time.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Do not try to use variable-width encoding to put IDs, as it&#039;ll work in small installations and break in larger ones.&lt;br /&gt;
&lt;br /&gt;
== Security issues ==&lt;br /&gt;
&lt;br /&gt;
Any code in modulename_process_email() _must_ assume it will see repeat replies and handle them gracefully. The definition of &#039;gracefully&#039; depends on what the code does.&lt;br /&gt;
&lt;br /&gt;
Email servers (MTAs) will sometimes re-transmit a message if they are unsure that the receiving MTA got it -- and sysadmins may sometimes replay a whole email queue if something&#039;s gone wrong. In that case, they email body will be identical, the headers slightly different.&lt;br /&gt;
&lt;br /&gt;
In a different case, the user may &#039;reply&#039; to the message twice. Perhaps in error, perhaps purposefully. What to do depends on the specific scenario.&lt;br /&gt;
&lt;br /&gt;
We /could/ support better protection at the framework level, by keeping track of every reply-to address we send out. We decided against that because (a) the performance impact will be important (b) we want the 1st cut to be lightweight and simple to change in case we need to.&lt;br /&gt;
&lt;br /&gt;
With this the initial implementation, modules should expose functions that handle these &amp;quot;replay&amp;quot; cases correctly. If later we want to expose additional functions, we can add such tracking as an optional thing. It&#039;d be awful to have it across all emails sent from Moodle.&lt;br /&gt;
&lt;br /&gt;
== Experimental email processing, pending merge into 1.9/2.0 ==&lt;br /&gt;
===Module Authors===&lt;br /&gt;
The email interface allows you to let users respond to emails sent via your module and affect change in them. The basic idea is that each email is uniquely identified with an email session that carries with it a simple payload. This payload is stored via database, and cannot be changed by the user. Replies are handled by module code in your lib.php library - modulename_process_email($payload, $body) - which is passed the session payload and the body (with full headers) of the email received, to be parsed as you like. Some utility functions are available as well to help with this.&lt;br /&gt;
&lt;br /&gt;
Here is an outline of the intended use:&lt;br /&gt;
* Before sending an email to a user via the email_to_user() function, the module should check to see if the config variable $CFG-&amp;gt;emailinterface is enabled. (This is off by default)&lt;br /&gt;
* Assuming the email interface is enabled, the function generate_email_verp_address($moduleid, $payload, $userid) should be called to create an &amp;quot;email session&amp;quot;. The payload should include any data you wish to use in your handling routine - such as the id of the user, or what part of the interface he is interacting with. The function will return a string containing the email session id.&lt;br /&gt;
* Call the email_to_user() function as normal, appending the email session id as the 11th parameter. Keep in mind that you will probably also need to change the text or html of the email to point out that the email interface is active.&lt;br /&gt;
* A function contained in the lib.php file of your module, named [modulename]_process_email($payload, $body) should be written. This is the handler function, which is called when an email reply is received. This function can inspect the contents of the payload received, then parse the email body for data. The $body parameter returns the full email, including the headers.&lt;br /&gt;
&lt;br /&gt;
Note that each email can only be replied to once - the email session is destroyed once an email has been received. If you wish to have multiple replies from a user, you will have to create a new session (and new email) every time. The email session table is also regularly pruned, the default settings allow sessions to persist for one month.&lt;br /&gt;
&lt;br /&gt;
The following utility functions are also defined in admin/process_email.php, which can help:&lt;br /&gt;
* get_email_subject($fullemail) - return the subject of an email&lt;br /&gt;
* strip_email_headers($fullemail) - strip all headers off an email&lt;br /&gt;
* email_is_multipart($fullemail) - determine if an email is a multipart message&lt;br /&gt;
* seperate_multipart($multipartmsg) - seperate a multipart email message into an array of parts, each of which has headers and a body.&lt;br /&gt;
* get_multipart_content_type($part) - determine the content-type of a multipart, generally text/plain or text/html.&lt;br /&gt;
* multipart_is_quoted_printable($part) - determine if a email part has been encoded with the quoted-printable encoding - some email clients tend to do this to html.&lt;br /&gt;
* decode_quoted_printable($partdata) - decode a email that has been encoded with quoted-printable encoding - this needs to be run on the data section of a part (strip_email_headers can be used to seperate the headers of a part).&lt;br /&gt;
* strip_email_reply($body, $ishtml, $identifier) - strip all irrelevant lines of an email message based on a unique identifier embedded within the original message. This is used to determine what is user input, and what is irrelevant data the email client has added.&lt;br /&gt;
* strip_email_reply_multi($body, $ishtml, $identifier) - as above, but allowing for multiple sections of possible user input in a single email message.&lt;br /&gt;
&lt;br /&gt;
Examples of use of these functions can be seen in the handler for the forum module. The idea behind the strip reply functions is that the original email will contain a unique identifier, such as a random 10 character string. This is embedded in a line with instructions for the user to write below and above it, e.g:&lt;br /&gt;
  \/ Please put your response here [ABCDEFGHIJ] \/&lt;br /&gt;
  &amp;lt;User Data&amp;gt;&lt;br /&gt;
  /\ Please put your response here [ABCDEFGHIJ] /\&lt;br /&gt;
This is necessary because of the wide differences between webmail and email clients in handling quotes and prefixing dates/times to replied emails. Keep in mind that text emails have an 80-character line width restrictions, which must also include the quote added by the email client, so any line of a text-email with this identifier should be kept to at least 77 characters to avoid wrapping by an email client. This unique identifier can be easily stored in the payload. Multiple input sections are handled similarly - a number is appended to the end of the identifier, e.g. [ABCDEFGHIJ1] to signfiy the first section of input. The strip_email_reply_multi returns an array containing a map from each numbered section it finds to a string containing all data in that section.&lt;br /&gt;
&lt;br /&gt;
===Developer Info===&lt;br /&gt;
The reply-to header is now encoded in base32 instead of base64 to allow for case-insensitive MTA&#039;s. Generate_email_processing_address was left as a backwards-compatibility wrapper, modules should use generate_email_verp_address now instead.&lt;br /&gt;
&lt;br /&gt;
Email sessions have been created to deal with the lack of space avaliable in the header under base32, payloads are stored in a new table mdl_email_sessions, and are identified with a unique base32 key which is embedded in the reply-to header. Each row has a timestamp, and the table is pruned during cleanup cron in admin/cron.php.&lt;br /&gt;
&lt;br /&gt;
Bounce detection is now linked in with the email interface - bounce detection is included in admin/process_email.php. Some new configuration variables have also been created to help configure these changes - $CFG-&amp;gt;emailinterface and $CFG-&amp;gt;emailsessiontime - and both have been added to the server settings admin page.&lt;br /&gt;
&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=File:Example.jpg&amp;diff=27337</id>
		<title>File:Example.jpg</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=File:Example.jpg&amp;diff=27337"/>
		<updated>2007-09-26T19:32:13Z</updated>

		<summary type="html">&lt;p&gt;Matm: How to edit text strings using Site Administration.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;How to edit text strings using Site Administration.&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27336</id>
		<title>Email processing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27336"/>
		<updated>2007-09-26T19:31:11Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* Email confirmation or registration words, and how to edit them. */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Features ==&lt;br /&gt;
&lt;br /&gt;
Moodle now makes better use of the SMTP protocol and email in general. Most of the benefits result from using a technique known as Variable Envelope Return Path (VERP).&lt;br /&gt;
&lt;br /&gt;
* Works on most modern MTAs (at least on Unix systems).&lt;br /&gt;
* All processing of bounces and replies is secured using HMAC-MD5-8.&lt;br /&gt;
* Bounces are handled correctly and increase a &amp;quot;bad email&amp;quot; score for the user.&lt;br /&gt;
* noreply@host address is now on Reply-to field, avoiding accidental pollution of users address books.&lt;br /&gt;
* noreply@host has an autorresponder&lt;br /&gt;
* Makes it easy for modules to send emails with a signed VERP reply-to.&lt;br /&gt;
* Handles receving of VERP replies: Validates the HMAC-MD5-8 signature and Dispatches the encoded request data to the relevant module&lt;br /&gt;
&lt;br /&gt;
== Moodle configuration ==&lt;br /&gt;
&lt;br /&gt;
Edit config.php to enable bounce handling, and setup Moodle to match your MTA configuration. Here&#039;s how. Uncomment these lines in config.php (if you cannot find them, copy them from config-dist.php):&lt;br /&gt;
&lt;br /&gt;
  // once handlebounces is true, we will be using VERP for the return address of every sent email&lt;br /&gt;
  $CFG-&amp;gt;handlebounces = true;&lt;br /&gt;
  // minimum bounces allowed per user&lt;br /&gt;
  $CFG-&amp;gt;minbounces = 10;&lt;br /&gt;
  // ratio of bad emails to sent emails&lt;br /&gt;
  // if we get more than 20% bounces &lt;br /&gt;
  // for a given user, his/her email is marked bad&lt;br /&gt;
  $CFG-&amp;gt;bounceratio = .20;&lt;br /&gt;
&lt;br /&gt;
Edit the $CFG-&amp;gt;maildomain line and one of the $CFG-&amp;gt;mailprefix lines (the one that matches your MTA).&lt;br /&gt;
&lt;br /&gt;
Make sure your server has a command-line PHP interpreter, and that it is able to connect to mysql (or postgres if relevant). If you are able to run cron.php from the commandline or from crontab, this means PHP is ok.&lt;br /&gt;
&lt;br /&gt;
Edit the process_email.php script to point to the location of your php binary. It will usually be &#039;&#039;/usr/bin/php&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Email confirmation or registration words, and how to edit them.==&lt;br /&gt;
*  Students receive a confirmation email when they create a user account.  This text can be found in the lang/?/moodle.php as the emailconfirmation &amp;quot;variable&amp;quot;.&lt;br /&gt;
* Students receive a welcome email when they enroll in a course.  This text can be found in the lang/?/moodle.php file as the welcometocoursetext &amp;quot;variable&amp;quot;.&lt;br /&gt;
*If you feel the need to edit this text, the best way to do this is to go to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit. Once you have done this, hit the &amp;quot;Switch lang directory&amp;quot; button, and do your editing.&lt;br /&gt;
*If you decide to get your hands dirty and work by editing the moodle.php directly, be careful to open the file only in a simple text editor like notepad or wordpad. &lt;br /&gt;
*Tip: Be careful with markup - as you edit, you must use &amp;quot; &amp;quot; for things like putting in hyperlinks, titles and targets. You MUST &#039;escape&#039; them by putting a \ before each &amp;quot;. If you don&#039;t the resulting page will appear blank. For example, the normal way to markup a hyperlink is:-&lt;br /&gt;
**&amp;lt;nowiki&amp;gt;&amp;lt;a href=&amp;quot;http://www.blah_blah&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt; If you do this in the moodle.php file, your edited text won&#039;t appear.&lt;br /&gt;
**Use &amp;lt;nowiki&amp;gt;&amp;lt;a href=\&amp;quot;http://www.blah_blah\&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
*Use the \ before each &amp;quot; when marking up things like target=\&amp;quot;_blank&amp;quot; and title=\&amp;quot;Blah blah\&amp;quot; and other similar codes.&lt;br /&gt;
*If you feel you must really go the route of editing the moodle.php file directly, save a copy of the file in its own folder (copy and paste the file in the same folder). That way, if it all goes wrong for you, all you have to do is delete the botched file and rename the &#039;copy of moodle.php&#039; back to &#039;moodle.php&#039; and you are back to square one, no harm done!&lt;br /&gt;
*Having said all that, it is best to do all your editing in the web interface by going to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit.&lt;br /&gt;
[[Image:Example.jpg]]&lt;br /&gt;
&lt;br /&gt;
Make sure &#039;&#039;process_email.php&#039;&#039; is executable by running &amp;quot;chmod ugo+rx process_email.php&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Setup under Postfix ==&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;|&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; and moodle installed under /var/www/moodle we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
== Setup under Qmail ==&lt;br /&gt;
&lt;br /&gt;
Depending on your setup, your aliases will be controlled by one or more of&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;/etc/aliases&#039;&#039;&lt;br /&gt;
* &#039;&#039;/var/qmail/alias/.qmail-PREFIX&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you edit /etc/aliases add a line like this (for a prefix of &#039;mdl&#039;):&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you create /var/qmail/alias/.qmail-PREFIX, just do&lt;br /&gt;
&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-mdl&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-noreply&lt;br /&gt;
&lt;br /&gt;
To this three letter prefix, we will add a &#039;-&#039; when sending and receiving messages. For more info, check out the manpage for dot-qmail.&lt;br /&gt;
&lt;br /&gt;
== Setup under Exim ==&lt;br /&gt;
&lt;br /&gt;
Open &#039;&#039;/etc/exim/exim.conf&#039;&#039; and add to trusted_users the user Apache and cron.php run as (usually &amp;quot;www-data&amp;quot; or &amp;quot;nobody&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;+&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
More documentation about Exim can be found [http://www.exim.org/docs.html here]. You may have to tell Exim not to lowercase the local-part.&lt;br /&gt;
&lt;br /&gt;
== Developer info ==&lt;br /&gt;
&lt;br /&gt;
Changed functions:&lt;br /&gt;
&lt;br /&gt;
* email_to_user() will set the envelope sender to a special bounce processing address (based on $CFG settings)&lt;br /&gt;
* email_to_user() will accept (and set) a reply-to header, to be generated by the module calling the function.&lt;br /&gt;
* associated string changes/additions&lt;br /&gt;
&lt;br /&gt;
New functions:&lt;br /&gt;
&lt;br /&gt;
* generate_email_processing_address() - ALWAYS use this to generate the reply-to header. reply-to header will look like this: (LIMIT: 64 chars total) prefix - EXACTLY four chars encodeded, packed, moduleid (0 for core) (2 chars) up to 42 chars for the modules to put anything they want it (can contain userid (or, eg for forum, postids to reply to), or anything really. 42 chars is ABSOLUTE LIMIT) 16 char hash (half an md5) of the first part of the address, together with a site &amp;quot;secret&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* moodle_process_email() - any non-module email processing goes here (currently used for processing bounces)&lt;br /&gt;
&lt;br /&gt;
New files:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/process_email.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This script needs to be called from your MTA for anything starting with the 3 char prefix described above (and optionally, the noreply address).&lt;br /&gt;
&lt;br /&gt;
How does it work? It will break down and unencode the email address into moduleid and validate the half md5 hash, and call $modname_process_email (if it exists). Arguments to these functions are: $modargs (any part of the email address that isn&#039;t the prefix, modid or the hash) and the contents of the email (read from STDIN).&lt;br /&gt;
&lt;br /&gt;
It doubles up as the noreplyaddress autorresponder if you configure it with that address as well. Replying with a friendly &amp;quot;this is not a real email address&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
== Module Authors ==&lt;br /&gt;
&lt;br /&gt;
Take a look at new functions moodle_process_email() and generate_email_processing_address() in moodlelib.php for ideas about how to&lt;br /&gt;
&lt;br /&gt;
* encode and unencode the arguments your module needs to do the processing&lt;br /&gt;
* how to deal with multiple &amp;quot;actions&amp;quot; for any given module.&lt;br /&gt;
&lt;br /&gt;
In a nutshell, users can send emails to Moodle using special dynamic addresses. These emails can trigger a call to a module function in the form of modulename_process_email($str, $bodyofemail). The $str part will be up to 42 characters of data generated by Moodle (presumably by your own module), and the $bodyofemailpart is the contents of the email (got by reading STDIN - usually generated by the users MUA).&lt;br /&gt;
&lt;br /&gt;
The 42 characters come from the &amp;quot;local part&amp;quot; of an email address (the part before the @ sign) which can have up to 64 chars. Out of those 64 chars, Moodle uses 22 characters, leaving you with 42 characters to encode data.&lt;br /&gt;
&lt;br /&gt;
What do we do with the 22 chars? Four go to the prefix, which we need to let the MTA know to pass the message to our script. Two go to identify the module ID so we know which module has generated the message (and so we dispatch the request to that module). The remaining 16 are a signature (HMAC-MD5-8) we use to authenticate the message.&lt;br /&gt;
&lt;br /&gt;
Forty-two characters isn&#039;t a lot (although it could be the answer to life, the universe, and everything!) so make sure you use those characters wisely.&lt;br /&gt;
&lt;br /&gt;
The most efficient way to encode database IDs in their full range (so that they can be placed in an email address) we have found is base64_encode(pack(&#039;V&#039;,2147483647)), which returns &amp;quot;/ / / / f w = =&amp;quot;. The two trailing &amp;quot;= =&amp;quot; are redundant and you can remove them (you&#039;ll need to reappend them when retrieving your data). Join your parameters as encoded IDs in positional slots for efficiency.&lt;br /&gt;
&lt;br /&gt;
To retrieve your data, use substr() to separate your parameters, and then unpack(&#039;V&#039;,base64_decode($str)). Note that it&#039;ll return a one-element array.&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Using &#039;V&#039; reaches 2147483647, half the range of mySQL&#039;s INT. Additionally, &#039;V&#039; behaves like a signed value, rather than an unsigned, so I suspect there&#039;s a bug in PHP&#039;s documentation of pack().&lt;br /&gt;
&lt;br /&gt;
With each ID taking 6-chars (8 chars if we find a way to use the full range of &#039;V&#039;), you have a limited number of parameters. If you need to encode more information, store it in the DB and send emails that point to your stored data. Remember to cleanup this temporary data after a safe period of time.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Do not try to use variable-width encoding to put IDs, as it&#039;ll work in small installations and break in larger ones.&lt;br /&gt;
&lt;br /&gt;
== Security issues ==&lt;br /&gt;
&lt;br /&gt;
Any code in modulename_process_email() _must_ assume it will see repeat replies and handle them gracefully. The definition of &#039;gracefully&#039; depends on what the code does.&lt;br /&gt;
&lt;br /&gt;
Email servers (MTAs) will sometimes re-transmit a message if they are unsure that the receiving MTA got it -- and sysadmins may sometimes replay a whole email queue if something&#039;s gone wrong. In that case, they email body will be identical, the headers slightly different.&lt;br /&gt;
&lt;br /&gt;
In a different case, the user may &#039;reply&#039; to the message twice. Perhaps in error, perhaps purposefully. What to do depends on the specific scenario.&lt;br /&gt;
&lt;br /&gt;
We /could/ support better protection at the framework level, by keeping track of every reply-to address we send out. We decided against that because (a) the performance impact will be important (b) we want the 1st cut to be lightweight and simple to change in case we need to.&lt;br /&gt;
&lt;br /&gt;
With this the initial implementation, modules should expose functions that handle these &amp;quot;replay&amp;quot; cases correctly. If later we want to expose additional functions, we can add such tracking as an optional thing. It&#039;d be awful to have it across all emails sent from Moodle.&lt;br /&gt;
&lt;br /&gt;
== Experimental email processing, pending merge into 1.9/2.0 ==&lt;br /&gt;
===Module Authors===&lt;br /&gt;
The email interface allows you to let users respond to emails sent via your module and affect change in them. The basic idea is that each email is uniquely identified with an email session that carries with it a simple payload. This payload is stored via database, and cannot be changed by the user. Replies are handled by module code in your lib.php library - modulename_process_email($payload, $body) - which is passed the session payload and the body (with full headers) of the email received, to be parsed as you like. Some utility functions are available as well to help with this.&lt;br /&gt;
&lt;br /&gt;
Here is an outline of the intended use:&lt;br /&gt;
* Before sending an email to a user via the email_to_user() function, the module should check to see if the config variable $CFG-&amp;gt;emailinterface is enabled. (This is off by default)&lt;br /&gt;
* Assuming the email interface is enabled, the function generate_email_verp_address($moduleid, $payload, $userid) should be called to create an &amp;quot;email session&amp;quot;. The payload should include any data you wish to use in your handling routine - such as the id of the user, or what part of the interface he is interacting with. The function will return a string containing the email session id.&lt;br /&gt;
* Call the email_to_user() function as normal, appending the email session id as the 11th parameter. Keep in mind that you will probably also need to change the text or html of the email to point out that the email interface is active.&lt;br /&gt;
* A function contained in the lib.php file of your module, named [modulename]_process_email($payload, $body) should be written. This is the handler function, which is called when an email reply is received. This function can inspect the contents of the payload received, then parse the email body for data. The $body parameter returns the full email, including the headers.&lt;br /&gt;
&lt;br /&gt;
Note that each email can only be replied to once - the email session is destroyed once an email has been received. If you wish to have multiple replies from a user, you will have to create a new session (and new email) every time. The email session table is also regularly pruned, the default settings allow sessions to persist for one month.&lt;br /&gt;
&lt;br /&gt;
The following utility functions are also defined in admin/process_email.php, which can help:&lt;br /&gt;
* get_email_subject($fullemail) - return the subject of an email&lt;br /&gt;
* strip_email_headers($fullemail) - strip all headers off an email&lt;br /&gt;
* email_is_multipart($fullemail) - determine if an email is a multipart message&lt;br /&gt;
* seperate_multipart($multipartmsg) - seperate a multipart email message into an array of parts, each of which has headers and a body.&lt;br /&gt;
* get_multipart_content_type($part) - determine the content-type of a multipart, generally text/plain or text/html.&lt;br /&gt;
* multipart_is_quoted_printable($part) - determine if a email part has been encoded with the quoted-printable encoding - some email clients tend to do this to html.&lt;br /&gt;
* decode_quoted_printable($partdata) - decode a email that has been encoded with quoted-printable encoding - this needs to be run on the data section of a part (strip_email_headers can be used to seperate the headers of a part).&lt;br /&gt;
* strip_email_reply($body, $ishtml, $identifier) - strip all irrelevant lines of an email message based on a unique identifier embedded within the original message. This is used to determine what is user input, and what is irrelevant data the email client has added.&lt;br /&gt;
* strip_email_reply_multi($body, $ishtml, $identifier) - as above, but allowing for multiple sections of possible user input in a single email message.&lt;br /&gt;
&lt;br /&gt;
Examples of use of these functions can be seen in the handler for the forum module. The idea behind the strip reply functions is that the original email will contain a unique identifier, such as a random 10 character string. This is embedded in a line with instructions for the user to write below and above it, e.g:&lt;br /&gt;
  \/ Please put your response here [ABCDEFGHIJ] \/&lt;br /&gt;
  &amp;lt;User Data&amp;gt;&lt;br /&gt;
  /\ Please put your response here [ABCDEFGHIJ] /\&lt;br /&gt;
This is necessary because of the wide differences between webmail and email clients in handling quotes and prefixing dates/times to replied emails. Keep in mind that text emails have an 80-character line width restrictions, which must also include the quote added by the email client, so any line of a text-email with this identifier should be kept to at least 77 characters to avoid wrapping by an email client. This unique identifier can be easily stored in the payload. Multiple input sections are handled similarly - a number is appended to the end of the identifier, e.g. [ABCDEFGHIJ1] to signfiy the first section of input. The strip_email_reply_multi returns an array containing a map from each numbered section it finds to a string containing all data in that section.&lt;br /&gt;
&lt;br /&gt;
===Developer Info===&lt;br /&gt;
The reply-to header is now encoded in base32 instead of base64 to allow for case-insensitive MTA&#039;s. Generate_email_processing_address was left as a backwards-compatibility wrapper, modules should use generate_email_verp_address now instead.&lt;br /&gt;
&lt;br /&gt;
Email sessions have been created to deal with the lack of space avaliable in the header under base32, payloads are stored in a new table mdl_email_sessions, and are identified with a unique base32 key which is embedded in the reply-to header. Each row has a timestamp, and the table is pruned during cleanup cron in admin/cron.php.&lt;br /&gt;
&lt;br /&gt;
Bounce detection is now linked in with the email interface - bounce detection is included in admin/process_email.php. Some new configuration variables have also been created to help configure these changes - $CFG-&amp;gt;emailinterface and $CFG-&amp;gt;emailsessiontime - and both have been added to the server settings admin page.&lt;br /&gt;
&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Sandbox&amp;diff=27335</id>
		<title>Sandbox</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Sandbox&amp;diff=27335"/>
		<updated>2007-09-26T19:29:53Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* The arrangement */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;$$ sqrt( x + y ) $$&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&lt;br /&gt;
== Professional Development ==&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{{Category:Capabilities|Question}}&lt;br /&gt;
&lt;br /&gt;
Very nice :-)&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Moodle is Great!&amp;lt;/strong&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;== אחת שתיים שלו ארבע&lt;br /&gt;
 ==== Headline text ==== Headline text ==&#039;&#039;&#039;Bold text&#039;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== The arrangement ==&lt;br /&gt;
&lt;br /&gt;
#We want you to read the material [text, comic or video] in a  lesson and do the questions at the end. &lt;br /&gt;
#We want you to read the background material that is supplied. &lt;br /&gt;
#We want you to log onto the forum and post answers to the questions posed&lt;br /&gt;
&lt;br /&gt;
There are no marks for this course - your supervisor will only know that you have successfully completed each lesson but will be able to see  your postings to the forum.&lt;br /&gt;
[[Image:Example.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Headline text == (This is a level-2 Headline).&lt;br /&gt;
&lt;br /&gt;
== Headline text ==&lt;br /&gt;
[http://www.yahoo.com YaHoooo!]&lt;br /&gt;
&lt;br /&gt;
== Aesthetic entymology to follow! ==&lt;br /&gt;
&amp;lt;hr size=5&amp;gt;  &lt;br /&gt;
&amp;lt;hr size=10&amp;gt;&lt;br /&gt;
&amp;lt;hr size=20&amp;gt;  &lt;br /&gt;
... well, that&#039;s too bad: &amp;lt;tt&amp;gt; I was expecting to be able to make larger headers! &amp;lt;i&amp;gt;[pout!]&amp;lt;/i&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Interesting.  Don&#039;t know much about HTML but &lt;br /&gt;
#remember this is a Mediawiki.   &lt;br /&gt;
#When I want to try something off the beaten track in MoodleDocs, I [http://meta.wikimedia.org/wiki/Help:Editing#Templates start here with a search on editing tips].&lt;br /&gt;
#Since I am a clutz, I created a web page using a word processor.  Then opened my browser and revealed the page code.  Then placed it below.   So you can make larger headers several ways. chris collman&lt;br /&gt;
::see examples below&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;span style=&#039;font-size:26.0pt&#039;&amp;gt;This is 26.opt test&amp;lt;/span&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Notice it still is a header just not the default font&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Let&#039;s&#039;&#039;&#039; have a go of this&lt;br /&gt;
&amp;lt;math&amp;gt;x^2 + \sin x = \infty &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== moodle ==&lt;br /&gt;
 business and see what the lark is all about!&lt;br /&gt;
&lt;br /&gt;
--[[User:Jonathan Foley|Jonathan Foley]] 08:42, 11 June 2007 (CDT)&lt;br /&gt;
&lt;br /&gt;
== Headline text ==&lt;br /&gt;
&lt;br /&gt;
Martha is a radical&lt;br /&gt;
&lt;br /&gt;
=Is a 1st level header - the larger header topic=&lt;br /&gt;
&lt;br /&gt;
just to see what would happen&lt;br /&gt;
&lt;br /&gt;
=&amp;lt;span style=&#039;font-size:40.0pt&#039;&amp;gt;This  is a 400.opt font test&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hmm...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Bold text&#039;&#039;&#039; test A&lt;br /&gt;
&lt;br /&gt;
Just testing it out!&lt;br /&gt;
&lt;br /&gt;
Seems OK!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Here&#039;s some text.&lt;br /&gt;
:Here&#039;s some indented text.&lt;br /&gt;
::And a bit more indented.&lt;br /&gt;
::::::::::Now you&#039;re just being silly.&lt;br /&gt;
::::Indeed!&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[fr:Bac à sable]]&lt;br /&gt;
[[ja:サンドボックス]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=User:Matt_Molloy&amp;diff=27334</id>
		<title>User:Matt Molloy</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=User:Matt_Molloy&amp;diff=27334"/>
		<updated>2007-09-26T19:12:12Z</updated>

		<summary type="html">&lt;p&gt;Matm: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Working in apprenticeship training and part-time university lecturer.&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27333</id>
		<title>Email processing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27333"/>
		<updated>2007-09-26T19:06:11Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* Email confirmation or registration words */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Features ==&lt;br /&gt;
&lt;br /&gt;
Moodle now makes better use of the SMTP protocol and email in general. Most of the benefits result from using a technique known as Variable Envelope Return Path (VERP).&lt;br /&gt;
&lt;br /&gt;
* Works on most modern MTAs (at least on Unix systems).&lt;br /&gt;
* All processing of bounces and replies is secured using HMAC-MD5-8.&lt;br /&gt;
* Bounces are handled correctly and increase a &amp;quot;bad email&amp;quot; score for the user.&lt;br /&gt;
* noreply@host address is now on Reply-to field, avoiding accidental pollution of users address books.&lt;br /&gt;
* noreply@host has an autorresponder&lt;br /&gt;
* Makes it easy for modules to send emails with a signed VERP reply-to.&lt;br /&gt;
* Handles receving of VERP replies: Validates the HMAC-MD5-8 signature and Dispatches the encoded request data to the relevant module&lt;br /&gt;
&lt;br /&gt;
== Moodle configuration ==&lt;br /&gt;
&lt;br /&gt;
Edit config.php to enable bounce handling, and setup Moodle to match your MTA configuration. Here&#039;s how. Uncomment these lines in config.php (if you cannot find them, copy them from config-dist.php):&lt;br /&gt;
&lt;br /&gt;
  // once handlebounces is true, we will be using VERP for the return address of every sent email&lt;br /&gt;
  $CFG-&amp;gt;handlebounces = true;&lt;br /&gt;
  // minimum bounces allowed per user&lt;br /&gt;
  $CFG-&amp;gt;minbounces = 10;&lt;br /&gt;
  // ratio of bad emails to sent emails&lt;br /&gt;
  // if we get more than 20% bounces &lt;br /&gt;
  // for a given user, his/her email is marked bad&lt;br /&gt;
  $CFG-&amp;gt;bounceratio = .20;&lt;br /&gt;
&lt;br /&gt;
Edit the $CFG-&amp;gt;maildomain line and one of the $CFG-&amp;gt;mailprefix lines (the one that matches your MTA).&lt;br /&gt;
&lt;br /&gt;
Make sure your server has a command-line PHP interpreter, and that it is able to connect to mysql (or postgres if relevant). If you are able to run cron.php from the commandline or from crontab, this means PHP is ok.&lt;br /&gt;
&lt;br /&gt;
Edit the process_email.php script to point to the location of your php binary. It will usually be &#039;&#039;/usr/bin/php&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Email confirmation or registration words, and how to edit them.==&lt;br /&gt;
*  Students receive a confirmation email when they create a user account.  This text can be found in the lang/?/moodle.php as the emailconfirmation &amp;quot;variable&amp;quot;.&lt;br /&gt;
* Students receive a welcome email when they enroll in a course.  This text can be found in the lang/?/moodle.php file as the welcometocoursetext &amp;quot;variable&amp;quot;.&lt;br /&gt;
*If you feel the need to edit this text, the best way to do this is to go to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit. Once you have done this, hit the &amp;quot;Switch lang directory&amp;quot; button, and do your editing.&lt;br /&gt;
*If you decide to get your hands dirty and work by editing the moodle.php directly, be careful to open the file only in a simple text editor like notepad or wordpad. &lt;br /&gt;
*Tip: Be careful with markup - as you edit, you must use &amp;quot; &amp;quot; for things like putting in hyperlinks, titles and targets. You MUST &#039;escape&#039; them by putting a \ before each &amp;quot;. If you don&#039;t the resulting page will appear blank. For example, the normal way to markup a hyperlink is:-&lt;br /&gt;
**&amp;lt;nowiki&amp;gt;&amp;lt;a href=&amp;quot;http://www.blah_blah&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt; If you do this in the moodle.php file, your edited text won&#039;t appear.&lt;br /&gt;
**Use &amp;lt;nowiki&amp;gt;&amp;lt;a href=\&amp;quot;http://www.blah_blah\&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
*Use the \ before each &amp;quot; when marking up things like target=\&amp;quot;_blank&amp;quot; and title=\&amp;quot;Blah blah\&amp;quot; and other similar codes.&lt;br /&gt;
*If you feel you must really go the route of editing the moodle.php file directly, save a copy of the file in its own folder (copy and paste the file in the same folder). That way, if it all goes wrong for you, all you have to do is delete the botched file and rename the &#039;copy of moodle.php&#039; back to &#039;moodle.php&#039; and you are back to square one, no harm done!&lt;br /&gt;
*Having said all that, it is best to do all your editing in the web interface by going to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Make sure &#039;&#039;process_email.php&#039;&#039; is executable by running &amp;quot;chmod ugo+rx process_email.php&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Setup under Postfix ==&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;|&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; and moodle installed under /var/www/moodle we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
== Setup under Qmail ==&lt;br /&gt;
&lt;br /&gt;
Depending on your setup, your aliases will be controlled by one or more of&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;/etc/aliases&#039;&#039;&lt;br /&gt;
* &#039;&#039;/var/qmail/alias/.qmail-PREFIX&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you edit /etc/aliases add a line like this (for a prefix of &#039;mdl&#039;):&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you create /var/qmail/alias/.qmail-PREFIX, just do&lt;br /&gt;
&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-mdl&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-noreply&lt;br /&gt;
&lt;br /&gt;
To this three letter prefix, we will add a &#039;-&#039; when sending and receiving messages. For more info, check out the manpage for dot-qmail.&lt;br /&gt;
&lt;br /&gt;
== Setup under Exim ==&lt;br /&gt;
&lt;br /&gt;
Open &#039;&#039;/etc/exim/exim.conf&#039;&#039; and add to trusted_users the user Apache and cron.php run as (usually &amp;quot;www-data&amp;quot; or &amp;quot;nobody&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;+&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
More documentation about Exim can be found [http://www.exim.org/docs.html here]. You may have to tell Exim not to lowercase the local-part.&lt;br /&gt;
&lt;br /&gt;
== Developer info ==&lt;br /&gt;
&lt;br /&gt;
Changed functions:&lt;br /&gt;
&lt;br /&gt;
* email_to_user() will set the envelope sender to a special bounce processing address (based on $CFG settings)&lt;br /&gt;
* email_to_user() will accept (and set) a reply-to header, to be generated by the module calling the function.&lt;br /&gt;
* associated string changes/additions&lt;br /&gt;
&lt;br /&gt;
New functions:&lt;br /&gt;
&lt;br /&gt;
* generate_email_processing_address() - ALWAYS use this to generate the reply-to header. reply-to header will look like this: (LIMIT: 64 chars total) prefix - EXACTLY four chars encodeded, packed, moduleid (0 for core) (2 chars) up to 42 chars for the modules to put anything they want it (can contain userid (or, eg for forum, postids to reply to), or anything really. 42 chars is ABSOLUTE LIMIT) 16 char hash (half an md5) of the first part of the address, together with a site &amp;quot;secret&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* moodle_process_email() - any non-module email processing goes here (currently used for processing bounces)&lt;br /&gt;
&lt;br /&gt;
New files:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/process_email.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This script needs to be called from your MTA for anything starting with the 3 char prefix described above (and optionally, the noreply address).&lt;br /&gt;
&lt;br /&gt;
How does it work? It will break down and unencode the email address into moduleid and validate the half md5 hash, and call $modname_process_email (if it exists). Arguments to these functions are: $modargs (any part of the email address that isn&#039;t the prefix, modid or the hash) and the contents of the email (read from STDIN).&lt;br /&gt;
&lt;br /&gt;
It doubles up as the noreplyaddress autorresponder if you configure it with that address as well. Replying with a friendly &amp;quot;this is not a real email address&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
== Module Authors ==&lt;br /&gt;
&lt;br /&gt;
Take a look at new functions moodle_process_email() and generate_email_processing_address() in moodlelib.php for ideas about how to&lt;br /&gt;
&lt;br /&gt;
* encode and unencode the arguments your module needs to do the processing&lt;br /&gt;
* how to deal with multiple &amp;quot;actions&amp;quot; for any given module.&lt;br /&gt;
&lt;br /&gt;
In a nutshell, users can send emails to Moodle using special dynamic addresses. These emails can trigger a call to a module function in the form of modulename_process_email($str, $bodyofemail). The $str part will be up to 42 characters of data generated by Moodle (presumably by your own module), and the $bodyofemailpart is the contents of the email (got by reading STDIN - usually generated by the users MUA).&lt;br /&gt;
&lt;br /&gt;
The 42 characters come from the &amp;quot;local part&amp;quot; of an email address (the part before the @ sign) which can have up to 64 chars. Out of those 64 chars, Moodle uses 22 characters, leaving you with 42 characters to encode data.&lt;br /&gt;
&lt;br /&gt;
What do we do with the 22 chars? Four go to the prefix, which we need to let the MTA know to pass the message to our script. Two go to identify the module ID so we know which module has generated the message (and so we dispatch the request to that module). The remaining 16 are a signature (HMAC-MD5-8) we use to authenticate the message.&lt;br /&gt;
&lt;br /&gt;
Forty-two characters isn&#039;t a lot (although it could be the answer to life, the universe, and everything!) so make sure you use those characters wisely.&lt;br /&gt;
&lt;br /&gt;
The most efficient way to encode database IDs in their full range (so that they can be placed in an email address) we have found is base64_encode(pack(&#039;V&#039;,2147483647)), which returns &amp;quot;/ / / / f w = =&amp;quot;. The two trailing &amp;quot;= =&amp;quot; are redundant and you can remove them (you&#039;ll need to reappend them when retrieving your data). Join your parameters as encoded IDs in positional slots for efficiency.&lt;br /&gt;
&lt;br /&gt;
To retrieve your data, use substr() to separate your parameters, and then unpack(&#039;V&#039;,base64_decode($str)). Note that it&#039;ll return a one-element array.&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Using &#039;V&#039; reaches 2147483647, half the range of mySQL&#039;s INT. Additionally, &#039;V&#039; behaves like a signed value, rather than an unsigned, so I suspect there&#039;s a bug in PHP&#039;s documentation of pack().&lt;br /&gt;
&lt;br /&gt;
With each ID taking 6-chars (8 chars if we find a way to use the full range of &#039;V&#039;), you have a limited number of parameters. If you need to encode more information, store it in the DB and send emails that point to your stored data. Remember to cleanup this temporary data after a safe period of time.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Do not try to use variable-width encoding to put IDs, as it&#039;ll work in small installations and break in larger ones.&lt;br /&gt;
&lt;br /&gt;
== Security issues ==&lt;br /&gt;
&lt;br /&gt;
Any code in modulename_process_email() _must_ assume it will see repeat replies and handle them gracefully. The definition of &#039;gracefully&#039; depends on what the code does.&lt;br /&gt;
&lt;br /&gt;
Email servers (MTAs) will sometimes re-transmit a message if they are unsure that the receiving MTA got it -- and sysadmins may sometimes replay a whole email queue if something&#039;s gone wrong. In that case, they email body will be identical, the headers slightly different.&lt;br /&gt;
&lt;br /&gt;
In a different case, the user may &#039;reply&#039; to the message twice. Perhaps in error, perhaps purposefully. What to do depends on the specific scenario.&lt;br /&gt;
&lt;br /&gt;
We /could/ support better protection at the framework level, by keeping track of every reply-to address we send out. We decided against that because (a) the performance impact will be important (b) we want the 1st cut to be lightweight and simple to change in case we need to.&lt;br /&gt;
&lt;br /&gt;
With this the initial implementation, modules should expose functions that handle these &amp;quot;replay&amp;quot; cases correctly. If later we want to expose additional functions, we can add such tracking as an optional thing. It&#039;d be awful to have it across all emails sent from Moodle.&lt;br /&gt;
&lt;br /&gt;
== Experimental email processing, pending merge into 1.9/2.0 ==&lt;br /&gt;
===Module Authors===&lt;br /&gt;
The email interface allows you to let users respond to emails sent via your module and affect change in them. The basic idea is that each email is uniquely identified with an email session that carries with it a simple payload. This payload is stored via database, and cannot be changed by the user. Replies are handled by module code in your lib.php library - modulename_process_email($payload, $body) - which is passed the session payload and the body (with full headers) of the email received, to be parsed as you like. Some utility functions are available as well to help with this.&lt;br /&gt;
&lt;br /&gt;
Here is an outline of the intended use:&lt;br /&gt;
* Before sending an email to a user via the email_to_user() function, the module should check to see if the config variable $CFG-&amp;gt;emailinterface is enabled. (This is off by default)&lt;br /&gt;
* Assuming the email interface is enabled, the function generate_email_verp_address($moduleid, $payload, $userid) should be called to create an &amp;quot;email session&amp;quot;. The payload should include any data you wish to use in your handling routine - such as the id of the user, or what part of the interface he is interacting with. The function will return a string containing the email session id.&lt;br /&gt;
* Call the email_to_user() function as normal, appending the email session id as the 11th parameter. Keep in mind that you will probably also need to change the text or html of the email to point out that the email interface is active.&lt;br /&gt;
* A function contained in the lib.php file of your module, named [modulename]_process_email($payload, $body) should be written. This is the handler function, which is called when an email reply is received. This function can inspect the contents of the payload received, then parse the email body for data. The $body parameter returns the full email, including the headers.&lt;br /&gt;
&lt;br /&gt;
Note that each email can only be replied to once - the email session is destroyed once an email has been received. If you wish to have multiple replies from a user, you will have to create a new session (and new email) every time. The email session table is also regularly pruned, the default settings allow sessions to persist for one month.&lt;br /&gt;
&lt;br /&gt;
The following utility functions are also defined in admin/process_email.php, which can help:&lt;br /&gt;
* get_email_subject($fullemail) - return the subject of an email&lt;br /&gt;
* strip_email_headers($fullemail) - strip all headers off an email&lt;br /&gt;
* email_is_multipart($fullemail) - determine if an email is a multipart message&lt;br /&gt;
* seperate_multipart($multipartmsg) - seperate a multipart email message into an array of parts, each of which has headers and a body.&lt;br /&gt;
* get_multipart_content_type($part) - determine the content-type of a multipart, generally text/plain or text/html.&lt;br /&gt;
* multipart_is_quoted_printable($part) - determine if a email part has been encoded with the quoted-printable encoding - some email clients tend to do this to html.&lt;br /&gt;
* decode_quoted_printable($partdata) - decode a email that has been encoded with quoted-printable encoding - this needs to be run on the data section of a part (strip_email_headers can be used to seperate the headers of a part).&lt;br /&gt;
* strip_email_reply($body, $ishtml, $identifier) - strip all irrelevant lines of an email message based on a unique identifier embedded within the original message. This is used to determine what is user input, and what is irrelevant data the email client has added.&lt;br /&gt;
* strip_email_reply_multi($body, $ishtml, $identifier) - as above, but allowing for multiple sections of possible user input in a single email message.&lt;br /&gt;
&lt;br /&gt;
Examples of use of these functions can be seen in the handler for the forum module. The idea behind the strip reply functions is that the original email will contain a unique identifier, such as a random 10 character string. This is embedded in a line with instructions for the user to write below and above it, e.g:&lt;br /&gt;
  \/ Please put your response here [ABCDEFGHIJ] \/&lt;br /&gt;
  &amp;lt;User Data&amp;gt;&lt;br /&gt;
  /\ Please put your response here [ABCDEFGHIJ] /\&lt;br /&gt;
This is necessary because of the wide differences between webmail and email clients in handling quotes and prefixing dates/times to replied emails. Keep in mind that text emails have an 80-character line width restrictions, which must also include the quote added by the email client, so any line of a text-email with this identifier should be kept to at least 77 characters to avoid wrapping by an email client. This unique identifier can be easily stored in the payload. Multiple input sections are handled similarly - a number is appended to the end of the identifier, e.g. [ABCDEFGHIJ1] to signfiy the first section of input. The strip_email_reply_multi returns an array containing a map from each numbered section it finds to a string containing all data in that section.&lt;br /&gt;
&lt;br /&gt;
===Developer Info===&lt;br /&gt;
The reply-to header is now encoded in base32 instead of base64 to allow for case-insensitive MTA&#039;s. Generate_email_processing_address was left as a backwards-compatibility wrapper, modules should use generate_email_verp_address now instead.&lt;br /&gt;
&lt;br /&gt;
Email sessions have been created to deal with the lack of space avaliable in the header under base32, payloads are stored in a new table mdl_email_sessions, and are identified with a unique base32 key which is embedded in the reply-to header. Each row has a timestamp, and the table is pruned during cleanup cron in admin/cron.php.&lt;br /&gt;
&lt;br /&gt;
Bounce detection is now linked in with the email interface - bounce detection is included in admin/process_email.php. Some new configuration variables have also been created to help configure these changes - $CFG-&amp;gt;emailinterface and $CFG-&amp;gt;emailsessiontime - and both have been added to the server settings admin page.&lt;br /&gt;
&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27332</id>
		<title>Email processing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27332"/>
		<updated>2007-09-26T19:05:09Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* Email confirmation or registration words, and how to edit them. */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Features ==&lt;br /&gt;
&lt;br /&gt;
Moodle now makes better use of the SMTP protocol and email in general. Most of the benefits result from using a technique known as Variable Envelope Return Path (VERP).&lt;br /&gt;
&lt;br /&gt;
* Works on most modern MTAs (at least on Unix systems).&lt;br /&gt;
* All processing of bounces and replies is secured using HMAC-MD5-8.&lt;br /&gt;
* Bounces are handled correctly and increase a &amp;quot;bad email&amp;quot; score for the user.&lt;br /&gt;
* noreply@host address is now on Reply-to field, avoiding accidental pollution of users address books.&lt;br /&gt;
* noreply@host has an autorresponder&lt;br /&gt;
* Makes it easy for modules to send emails with a signed VERP reply-to.&lt;br /&gt;
* Handles receving of VERP replies: Validates the HMAC-MD5-8 signature and Dispatches the encoded request data to the relevant module&lt;br /&gt;
&lt;br /&gt;
== Moodle configuration ==&lt;br /&gt;
&lt;br /&gt;
Edit config.php to enable bounce handling, and setup Moodle to match your MTA configuration. Here&#039;s how. Uncomment these lines in config.php (if you cannot find them, copy them from config-dist.php):&lt;br /&gt;
&lt;br /&gt;
  // once handlebounces is true, we will be using VERP for the return address of every sent email&lt;br /&gt;
  $CFG-&amp;gt;handlebounces = true;&lt;br /&gt;
  // minimum bounces allowed per user&lt;br /&gt;
  $CFG-&amp;gt;minbounces = 10;&lt;br /&gt;
  // ratio of bad emails to sent emails&lt;br /&gt;
  // if we get more than 20% bounces &lt;br /&gt;
  // for a given user, his/her email is marked bad&lt;br /&gt;
  $CFG-&amp;gt;bounceratio = .20;&lt;br /&gt;
&lt;br /&gt;
Edit the $CFG-&amp;gt;maildomain line and one of the $CFG-&amp;gt;mailprefix lines (the one that matches your MTA).&lt;br /&gt;
&lt;br /&gt;
Make sure your server has a command-line PHP interpreter, and that it is able to connect to mysql (or postgres if relevant). If you are able to run cron.php from the commandline or from crontab, this means PHP is ok.&lt;br /&gt;
&lt;br /&gt;
Edit the process_email.php script to point to the location of your php binary. It will usually be &#039;&#039;/usr/bin/php&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Email confirmation or registration words==&lt;br /&gt;
*  Students receive a confirmation email when they create a user account.  This text can be found in the lang/?/moodle.php as the emailconfirmation &amp;quot;variable&amp;quot;.&lt;br /&gt;
* Students receive a welcome email when they enroll in a course.  This text can be found in the lang/?/moodle.php file as the welcometocoursetext &amp;quot;variable&amp;quot;.&lt;br /&gt;
*If you feel the need to edit this text, the best way to do this is to go to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit. Once you have done this, hit the &amp;quot;Switch lang directory&amp;quot; button, and do your editing.&lt;br /&gt;
*If you decide to get your hands dirty and work by editing the moodle.php directly, be careful to open the file only in a simple text editor like notepad or wordpad. &lt;br /&gt;
*Tip: Be careful with markup - as you edit, you must use &amp;quot; &amp;quot; for things like putting in hyperlinks, titles and targets. You MUST &#039;escape&#039; them by putting a \ before each &amp;quot;. If you don&#039;t the resulting page will appear blank. For example, the normal way to markup a hyperlink is:-&lt;br /&gt;
**&amp;lt;nowiki&amp;gt;&amp;lt;a href=&amp;quot;http://www.blah_blah&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt; If you do this in the moodle.php file, your edited text won&#039;t appear.&lt;br /&gt;
**Use &amp;lt;nowiki&amp;gt;&amp;lt;a href=\&amp;quot;http://www.blah_blah\&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
*Use the \ before each &amp;quot; when marking up things like target=\&amp;quot;_blank&amp;quot; and title=\&amp;quot;Blah blah\&amp;quot; and other similar codes.&lt;br /&gt;
*If you feel you must really go the route of editing the moodle.php file directly, save a copy of the file in its own folder (copy and paste the file in the same folder). That way, if it all goes wrong for you, all you have to do is delete the botched file and rename the &#039;copy of moodle.php&#039; back to &#039;moodle.php&#039; and you are back to square one, no harm done!&lt;br /&gt;
*Having said all that, it is best to do all your editing in the web interface by going to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Make sure &#039;&#039;process_email.php&#039;&#039; is executable by running &amp;quot;chmod ugo+rx process_email.php&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Setup under Postfix ==&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;|&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; and moodle installed under /var/www/moodle we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
== Setup under Qmail ==&lt;br /&gt;
&lt;br /&gt;
Depending on your setup, your aliases will be controlled by one or more of&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;/etc/aliases&#039;&#039;&lt;br /&gt;
* &#039;&#039;/var/qmail/alias/.qmail-PREFIX&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you edit /etc/aliases add a line like this (for a prefix of &#039;mdl&#039;):&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you create /var/qmail/alias/.qmail-PREFIX, just do&lt;br /&gt;
&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-mdl&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-noreply&lt;br /&gt;
&lt;br /&gt;
To this three letter prefix, we will add a &#039;-&#039; when sending and receiving messages. For more info, check out the manpage for dot-qmail.&lt;br /&gt;
&lt;br /&gt;
== Setup under Exim ==&lt;br /&gt;
&lt;br /&gt;
Open &#039;&#039;/etc/exim/exim.conf&#039;&#039; and add to trusted_users the user Apache and cron.php run as (usually &amp;quot;www-data&amp;quot; or &amp;quot;nobody&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;+&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
More documentation about Exim can be found [http://www.exim.org/docs.html here]. You may have to tell Exim not to lowercase the local-part.&lt;br /&gt;
&lt;br /&gt;
== Developer info ==&lt;br /&gt;
&lt;br /&gt;
Changed functions:&lt;br /&gt;
&lt;br /&gt;
* email_to_user() will set the envelope sender to a special bounce processing address (based on $CFG settings)&lt;br /&gt;
* email_to_user() will accept (and set) a reply-to header, to be generated by the module calling the function.&lt;br /&gt;
* associated string changes/additions&lt;br /&gt;
&lt;br /&gt;
New functions:&lt;br /&gt;
&lt;br /&gt;
* generate_email_processing_address() - ALWAYS use this to generate the reply-to header. reply-to header will look like this: (LIMIT: 64 chars total) prefix - EXACTLY four chars encodeded, packed, moduleid (0 for core) (2 chars) up to 42 chars for the modules to put anything they want it (can contain userid (or, eg for forum, postids to reply to), or anything really. 42 chars is ABSOLUTE LIMIT) 16 char hash (half an md5) of the first part of the address, together with a site &amp;quot;secret&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* moodle_process_email() - any non-module email processing goes here (currently used for processing bounces)&lt;br /&gt;
&lt;br /&gt;
New files:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/process_email.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This script needs to be called from your MTA for anything starting with the 3 char prefix described above (and optionally, the noreply address).&lt;br /&gt;
&lt;br /&gt;
How does it work? It will break down and unencode the email address into moduleid and validate the half md5 hash, and call $modname_process_email (if it exists). Arguments to these functions are: $modargs (any part of the email address that isn&#039;t the prefix, modid or the hash) and the contents of the email (read from STDIN).&lt;br /&gt;
&lt;br /&gt;
It doubles up as the noreplyaddress autorresponder if you configure it with that address as well. Replying with a friendly &amp;quot;this is not a real email address&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
== Module Authors ==&lt;br /&gt;
&lt;br /&gt;
Take a look at new functions moodle_process_email() and generate_email_processing_address() in moodlelib.php for ideas about how to&lt;br /&gt;
&lt;br /&gt;
* encode and unencode the arguments your module needs to do the processing&lt;br /&gt;
* how to deal with multiple &amp;quot;actions&amp;quot; for any given module.&lt;br /&gt;
&lt;br /&gt;
In a nutshell, users can send emails to Moodle using special dynamic addresses. These emails can trigger a call to a module function in the form of modulename_process_email($str, $bodyofemail). The $str part will be up to 42 characters of data generated by Moodle (presumably by your own module), and the $bodyofemailpart is the contents of the email (got by reading STDIN - usually generated by the users MUA).&lt;br /&gt;
&lt;br /&gt;
The 42 characters come from the &amp;quot;local part&amp;quot; of an email address (the part before the @ sign) which can have up to 64 chars. Out of those 64 chars, Moodle uses 22 characters, leaving you with 42 characters to encode data.&lt;br /&gt;
&lt;br /&gt;
What do we do with the 22 chars? Four go to the prefix, which we need to let the MTA know to pass the message to our script. Two go to identify the module ID so we know which module has generated the message (and so we dispatch the request to that module). The remaining 16 are a signature (HMAC-MD5-8) we use to authenticate the message.&lt;br /&gt;
&lt;br /&gt;
Forty-two characters isn&#039;t a lot (although it could be the answer to life, the universe, and everything!) so make sure you use those characters wisely.&lt;br /&gt;
&lt;br /&gt;
The most efficient way to encode database IDs in their full range (so that they can be placed in an email address) we have found is base64_encode(pack(&#039;V&#039;,2147483647)), which returns &amp;quot;/ / / / f w = =&amp;quot;. The two trailing &amp;quot;= =&amp;quot; are redundant and you can remove them (you&#039;ll need to reappend them when retrieving your data). Join your parameters as encoded IDs in positional slots for efficiency.&lt;br /&gt;
&lt;br /&gt;
To retrieve your data, use substr() to separate your parameters, and then unpack(&#039;V&#039;,base64_decode($str)). Note that it&#039;ll return a one-element array.&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Using &#039;V&#039; reaches 2147483647, half the range of mySQL&#039;s INT. Additionally, &#039;V&#039; behaves like a signed value, rather than an unsigned, so I suspect there&#039;s a bug in PHP&#039;s documentation of pack().&lt;br /&gt;
&lt;br /&gt;
With each ID taking 6-chars (8 chars if we find a way to use the full range of &#039;V&#039;), you have a limited number of parameters. If you need to encode more information, store it in the DB and send emails that point to your stored data. Remember to cleanup this temporary data after a safe period of time.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Do not try to use variable-width encoding to put IDs, as it&#039;ll work in small installations and break in larger ones.&lt;br /&gt;
&lt;br /&gt;
== Security issues ==&lt;br /&gt;
&lt;br /&gt;
Any code in modulename_process_email() _must_ assume it will see repeat replies and handle them gracefully. The definition of &#039;gracefully&#039; depends on what the code does.&lt;br /&gt;
&lt;br /&gt;
Email servers (MTAs) will sometimes re-transmit a message if they are unsure that the receiving MTA got it -- and sysadmins may sometimes replay a whole email queue if something&#039;s gone wrong. In that case, they email body will be identical, the headers slightly different.&lt;br /&gt;
&lt;br /&gt;
In a different case, the user may &#039;reply&#039; to the message twice. Perhaps in error, perhaps purposefully. What to do depends on the specific scenario.&lt;br /&gt;
&lt;br /&gt;
We /could/ support better protection at the framework level, by keeping track of every reply-to address we send out. We decided against that because (a) the performance impact will be important (b) we want the 1st cut to be lightweight and simple to change in case we need to.&lt;br /&gt;
&lt;br /&gt;
With this the initial implementation, modules should expose functions that handle these &amp;quot;replay&amp;quot; cases correctly. If later we want to expose additional functions, we can add such tracking as an optional thing. It&#039;d be awful to have it across all emails sent from Moodle.&lt;br /&gt;
&lt;br /&gt;
== Experimental email processing, pending merge into 1.9/2.0 ==&lt;br /&gt;
===Module Authors===&lt;br /&gt;
The email interface allows you to let users respond to emails sent via your module and affect change in them. The basic idea is that each email is uniquely identified with an email session that carries with it a simple payload. This payload is stored via database, and cannot be changed by the user. Replies are handled by module code in your lib.php library - modulename_process_email($payload, $body) - which is passed the session payload and the body (with full headers) of the email received, to be parsed as you like. Some utility functions are available as well to help with this.&lt;br /&gt;
&lt;br /&gt;
Here is an outline of the intended use:&lt;br /&gt;
* Before sending an email to a user via the email_to_user() function, the module should check to see if the config variable $CFG-&amp;gt;emailinterface is enabled. (This is off by default)&lt;br /&gt;
* Assuming the email interface is enabled, the function generate_email_verp_address($moduleid, $payload, $userid) should be called to create an &amp;quot;email session&amp;quot;. The payload should include any data you wish to use in your handling routine - such as the id of the user, or what part of the interface he is interacting with. The function will return a string containing the email session id.&lt;br /&gt;
* Call the email_to_user() function as normal, appending the email session id as the 11th parameter. Keep in mind that you will probably also need to change the text or html of the email to point out that the email interface is active.&lt;br /&gt;
* A function contained in the lib.php file of your module, named [modulename]_process_email($payload, $body) should be written. This is the handler function, which is called when an email reply is received. This function can inspect the contents of the payload received, then parse the email body for data. The $body parameter returns the full email, including the headers.&lt;br /&gt;
&lt;br /&gt;
Note that each email can only be replied to once - the email session is destroyed once an email has been received. If you wish to have multiple replies from a user, you will have to create a new session (and new email) every time. The email session table is also regularly pruned, the default settings allow sessions to persist for one month.&lt;br /&gt;
&lt;br /&gt;
The following utility functions are also defined in admin/process_email.php, which can help:&lt;br /&gt;
* get_email_subject($fullemail) - return the subject of an email&lt;br /&gt;
* strip_email_headers($fullemail) - strip all headers off an email&lt;br /&gt;
* email_is_multipart($fullemail) - determine if an email is a multipart message&lt;br /&gt;
* seperate_multipart($multipartmsg) - seperate a multipart email message into an array of parts, each of which has headers and a body.&lt;br /&gt;
* get_multipart_content_type($part) - determine the content-type of a multipart, generally text/plain or text/html.&lt;br /&gt;
* multipart_is_quoted_printable($part) - determine if a email part has been encoded with the quoted-printable encoding - some email clients tend to do this to html.&lt;br /&gt;
* decode_quoted_printable($partdata) - decode a email that has been encoded with quoted-printable encoding - this needs to be run on the data section of a part (strip_email_headers can be used to seperate the headers of a part).&lt;br /&gt;
* strip_email_reply($body, $ishtml, $identifier) - strip all irrelevant lines of an email message based on a unique identifier embedded within the original message. This is used to determine what is user input, and what is irrelevant data the email client has added.&lt;br /&gt;
* strip_email_reply_multi($body, $ishtml, $identifier) - as above, but allowing for multiple sections of possible user input in a single email message.&lt;br /&gt;
&lt;br /&gt;
Examples of use of these functions can be seen in the handler for the forum module. The idea behind the strip reply functions is that the original email will contain a unique identifier, such as a random 10 character string. This is embedded in a line with instructions for the user to write below and above it, e.g:&lt;br /&gt;
  \/ Please put your response here [ABCDEFGHIJ] \/&lt;br /&gt;
  &amp;lt;User Data&amp;gt;&lt;br /&gt;
  /\ Please put your response here [ABCDEFGHIJ] /\&lt;br /&gt;
This is necessary because of the wide differences between webmail and email clients in handling quotes and prefixing dates/times to replied emails. Keep in mind that text emails have an 80-character line width restrictions, which must also include the quote added by the email client, so any line of a text-email with this identifier should be kept to at least 77 characters to avoid wrapping by an email client. This unique identifier can be easily stored in the payload. Multiple input sections are handled similarly - a number is appended to the end of the identifier, e.g. [ABCDEFGHIJ1] to signfiy the first section of input. The strip_email_reply_multi returns an array containing a map from each numbered section it finds to a string containing all data in that section.&lt;br /&gt;
&lt;br /&gt;
===Developer Info===&lt;br /&gt;
The reply-to header is now encoded in base32 instead of base64 to allow for case-insensitive MTA&#039;s. Generate_email_processing_address was left as a backwards-compatibility wrapper, modules should use generate_email_verp_address now instead.&lt;br /&gt;
&lt;br /&gt;
Email sessions have been created to deal with the lack of space avaliable in the header under base32, payloads are stored in a new table mdl_email_sessions, and are identified with a unique base32 key which is embedded in the reply-to header. Each row has a timestamp, and the table is pruned during cleanup cron in admin/cron.php.&lt;br /&gt;
&lt;br /&gt;
Bounce detection is now linked in with the email interface - bounce detection is included in admin/process_email.php. Some new configuration variables have also been created to help configure these changes - $CFG-&amp;gt;emailinterface and $CFG-&amp;gt;emailsessiontime - and both have been added to the server settings admin page.&lt;br /&gt;
&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27331</id>
		<title>Email processing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27331"/>
		<updated>2007-09-26T18:52:53Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* Email confirmation or registration words */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Features ==&lt;br /&gt;
&lt;br /&gt;
Moodle now makes better use of the SMTP protocol and email in general. Most of the benefits result from using a technique known as Variable Envelope Return Path (VERP).&lt;br /&gt;
&lt;br /&gt;
* Works on most modern MTAs (at least on Unix systems).&lt;br /&gt;
* All processing of bounces and replies is secured using HMAC-MD5-8.&lt;br /&gt;
* Bounces are handled correctly and increase a &amp;quot;bad email&amp;quot; score for the user.&lt;br /&gt;
* noreply@host address is now on Reply-to field, avoiding accidental pollution of users address books.&lt;br /&gt;
* noreply@host has an autorresponder&lt;br /&gt;
* Makes it easy for modules to send emails with a signed VERP reply-to.&lt;br /&gt;
* Handles receving of VERP replies: Validates the HMAC-MD5-8 signature and Dispatches the encoded request data to the relevant module&lt;br /&gt;
&lt;br /&gt;
== Moodle configuration ==&lt;br /&gt;
&lt;br /&gt;
Edit config.php to enable bounce handling, and setup Moodle to match your MTA configuration. Here&#039;s how. Uncomment these lines in config.php (if you cannot find them, copy them from config-dist.php):&lt;br /&gt;
&lt;br /&gt;
  // once handlebounces is true, we will be using VERP for the return address of every sent email&lt;br /&gt;
  $CFG-&amp;gt;handlebounces = true;&lt;br /&gt;
  // minimum bounces allowed per user&lt;br /&gt;
  $CFG-&amp;gt;minbounces = 10;&lt;br /&gt;
  // ratio of bad emails to sent emails&lt;br /&gt;
  // if we get more than 20% bounces &lt;br /&gt;
  // for a given user, his/her email is marked bad&lt;br /&gt;
  $CFG-&amp;gt;bounceratio = .20;&lt;br /&gt;
&lt;br /&gt;
Edit the $CFG-&amp;gt;maildomain line and one of the $CFG-&amp;gt;mailprefix lines (the one that matches your MTA).&lt;br /&gt;
&lt;br /&gt;
Make sure your server has a command-line PHP interpreter, and that it is able to connect to mysql (or postgres if relevant). If you are able to run cron.php from the commandline or from crontab, this means PHP is ok.&lt;br /&gt;
&lt;br /&gt;
Edit the process_email.php script to point to the location of your php binary. It will usually be &#039;&#039;/usr/bin/php&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Email confirmation or registration words==&lt;br /&gt;
*  Students receive a confirmation email when they create a user account.  This text can be found in the lang/?/moodle.php as the emailconfirmation &amp;quot;variable&amp;quot;.&lt;br /&gt;
* Students receive a welcome email when they enroll in a course.  This text can be found in the lang/?/moodle.php file as the welcometocoursetext &amp;quot;variable&amp;quot;.&lt;br /&gt;
*If you feel the need to edit this text, the best way to do this is to go to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit. Once you have done this, hit the &amp;quot;Switch lang directory&amp;quot; button, and do your editing.&lt;br /&gt;
*If you decide to get your hands dirty and work by editing the moodle.php directly, be careful to open the file only in a simple text editor like notepad or wordpad. &lt;br /&gt;
*Tip: Be careful with markup - as you edit, you must use &amp;quot; &amp;quot; for things like putting in hyperlinks, titles and targets. You MUST &#039;escape&#039; them by putting a \ before each &amp;quot;. If you don&#039;t the resulting page will appear blank. For example, the normal way to markup a hyperlink is:-&lt;br /&gt;
**&amp;lt;nowiki&amp;gt;&amp;lt;a href=&amp;quot;http://www.blah_blah&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt; If you do this in the moodle.php file, your edited text won&#039;t appear.&lt;br /&gt;
**Use &amp;lt;nowiki&amp;gt;&amp;lt;a href=\&amp;quot;http://www.blah_blah\&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
*Use the \ before each &amp;quot; when marking up things like target=\&amp;quot;_blank&amp;quot; and title=\&amp;quot;Blah blah\&amp;quot; and other similar codes.&lt;br /&gt;
*If you feel you must really go the route of editing the moodle.php file directly, save a copy of the file in its own folder (copy and paste the file in the same folder). That way, if it all goes wrong for you, all you have to do is delete the botched file and rename the &#039;copy of moodle.php&#039; back to &#039;moodle.php&#039; and you are back to square one, no harm done!&lt;br /&gt;
*Having said all that, it is best to do all your editing in the web interface by going to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit.&lt;br /&gt;
&lt;br /&gt;
Make sure &#039;&#039;process_email.php&#039;&#039; is executable by running &amp;quot;chmod ugo+rx process_email.php&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Setup under Postfix ==&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;|&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; and moodle installed under /var/www/moodle we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
== Setup under Qmail ==&lt;br /&gt;
&lt;br /&gt;
Depending on your setup, your aliases will be controlled by one or more of&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;/etc/aliases&#039;&#039;&lt;br /&gt;
* &#039;&#039;/var/qmail/alias/.qmail-PREFIX&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you edit /etc/aliases add a line like this (for a prefix of &#039;mdl&#039;):&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you create /var/qmail/alias/.qmail-PREFIX, just do&lt;br /&gt;
&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-mdl&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-noreply&lt;br /&gt;
&lt;br /&gt;
To this three letter prefix, we will add a &#039;-&#039; when sending and receiving messages. For more info, check out the manpage for dot-qmail.&lt;br /&gt;
&lt;br /&gt;
== Setup under Exim ==&lt;br /&gt;
&lt;br /&gt;
Open &#039;&#039;/etc/exim/exim.conf&#039;&#039; and add to trusted_users the user Apache and cron.php run as (usually &amp;quot;www-data&amp;quot; or &amp;quot;nobody&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;+&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
More documentation about Exim can be found [http://www.exim.org/docs.html here]. You may have to tell Exim not to lowercase the local-part.&lt;br /&gt;
&lt;br /&gt;
== Developer info ==&lt;br /&gt;
&lt;br /&gt;
Changed functions:&lt;br /&gt;
&lt;br /&gt;
* email_to_user() will set the envelope sender to a special bounce processing address (based on $CFG settings)&lt;br /&gt;
* email_to_user() will accept (and set) a reply-to header, to be generated by the module calling the function.&lt;br /&gt;
* associated string changes/additions&lt;br /&gt;
&lt;br /&gt;
New functions:&lt;br /&gt;
&lt;br /&gt;
* generate_email_processing_address() - ALWAYS use this to generate the reply-to header. reply-to header will look like this: (LIMIT: 64 chars total) prefix - EXACTLY four chars encodeded, packed, moduleid (0 for core) (2 chars) up to 42 chars for the modules to put anything they want it (can contain userid (or, eg for forum, postids to reply to), or anything really. 42 chars is ABSOLUTE LIMIT) 16 char hash (half an md5) of the first part of the address, together with a site &amp;quot;secret&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* moodle_process_email() - any non-module email processing goes here (currently used for processing bounces)&lt;br /&gt;
&lt;br /&gt;
New files:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/process_email.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This script needs to be called from your MTA for anything starting with the 3 char prefix described above (and optionally, the noreply address).&lt;br /&gt;
&lt;br /&gt;
How does it work? It will break down and unencode the email address into moduleid and validate the half md5 hash, and call $modname_process_email (if it exists). Arguments to these functions are: $modargs (any part of the email address that isn&#039;t the prefix, modid or the hash) and the contents of the email (read from STDIN).&lt;br /&gt;
&lt;br /&gt;
It doubles up as the noreplyaddress autorresponder if you configure it with that address as well. Replying with a friendly &amp;quot;this is not a real email address&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
== Module Authors ==&lt;br /&gt;
&lt;br /&gt;
Take a look at new functions moodle_process_email() and generate_email_processing_address() in moodlelib.php for ideas about how to&lt;br /&gt;
&lt;br /&gt;
* encode and unencode the arguments your module needs to do the processing&lt;br /&gt;
* how to deal with multiple &amp;quot;actions&amp;quot; for any given module.&lt;br /&gt;
&lt;br /&gt;
In a nutshell, users can send emails to Moodle using special dynamic addresses. These emails can trigger a call to a module function in the form of modulename_process_email($str, $bodyofemail). The $str part will be up to 42 characters of data generated by Moodle (presumably by your own module), and the $bodyofemailpart is the contents of the email (got by reading STDIN - usually generated by the users MUA).&lt;br /&gt;
&lt;br /&gt;
The 42 characters come from the &amp;quot;local part&amp;quot; of an email address (the part before the @ sign) which can have up to 64 chars. Out of those 64 chars, Moodle uses 22 characters, leaving you with 42 characters to encode data.&lt;br /&gt;
&lt;br /&gt;
What do we do with the 22 chars? Four go to the prefix, which we need to let the MTA know to pass the message to our script. Two go to identify the module ID so we know which module has generated the message (and so we dispatch the request to that module). The remaining 16 are a signature (HMAC-MD5-8) we use to authenticate the message.&lt;br /&gt;
&lt;br /&gt;
Forty-two characters isn&#039;t a lot (although it could be the answer to life, the universe, and everything!) so make sure you use those characters wisely.&lt;br /&gt;
&lt;br /&gt;
The most efficient way to encode database IDs in their full range (so that they can be placed in an email address) we have found is base64_encode(pack(&#039;V&#039;,2147483647)), which returns &amp;quot;/ / / / f w = =&amp;quot;. The two trailing &amp;quot;= =&amp;quot; are redundant and you can remove them (you&#039;ll need to reappend them when retrieving your data). Join your parameters as encoded IDs in positional slots for efficiency.&lt;br /&gt;
&lt;br /&gt;
To retrieve your data, use substr() to separate your parameters, and then unpack(&#039;V&#039;,base64_decode($str)). Note that it&#039;ll return a one-element array.&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Using &#039;V&#039; reaches 2147483647, half the range of mySQL&#039;s INT. Additionally, &#039;V&#039; behaves like a signed value, rather than an unsigned, so I suspect there&#039;s a bug in PHP&#039;s documentation of pack().&lt;br /&gt;
&lt;br /&gt;
With each ID taking 6-chars (8 chars if we find a way to use the full range of &#039;V&#039;), you have a limited number of parameters. If you need to encode more information, store it in the DB and send emails that point to your stored data. Remember to cleanup this temporary data after a safe period of time.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Do not try to use variable-width encoding to put IDs, as it&#039;ll work in small installations and break in larger ones.&lt;br /&gt;
&lt;br /&gt;
== Security issues ==&lt;br /&gt;
&lt;br /&gt;
Any code in modulename_process_email() _must_ assume it will see repeat replies and handle them gracefully. The definition of &#039;gracefully&#039; depends on what the code does.&lt;br /&gt;
&lt;br /&gt;
Email servers (MTAs) will sometimes re-transmit a message if they are unsure that the receiving MTA got it -- and sysadmins may sometimes replay a whole email queue if something&#039;s gone wrong. In that case, they email body will be identical, the headers slightly different.&lt;br /&gt;
&lt;br /&gt;
In a different case, the user may &#039;reply&#039; to the message twice. Perhaps in error, perhaps purposefully. What to do depends on the specific scenario.&lt;br /&gt;
&lt;br /&gt;
We /could/ support better protection at the framework level, by keeping track of every reply-to address we send out. We decided against that because (a) the performance impact will be important (b) we want the 1st cut to be lightweight and simple to change in case we need to.&lt;br /&gt;
&lt;br /&gt;
With this the initial implementation, modules should expose functions that handle these &amp;quot;replay&amp;quot; cases correctly. If later we want to expose additional functions, we can add such tracking as an optional thing. It&#039;d be awful to have it across all emails sent from Moodle.&lt;br /&gt;
&lt;br /&gt;
== Experimental email processing, pending merge into 1.9/2.0 ==&lt;br /&gt;
===Module Authors===&lt;br /&gt;
The email interface allows you to let users respond to emails sent via your module and affect change in them. The basic idea is that each email is uniquely identified with an email session that carries with it a simple payload. This payload is stored via database, and cannot be changed by the user. Replies are handled by module code in your lib.php library - modulename_process_email($payload, $body) - which is passed the session payload and the body (with full headers) of the email received, to be parsed as you like. Some utility functions are available as well to help with this.&lt;br /&gt;
&lt;br /&gt;
Here is an outline of the intended use:&lt;br /&gt;
* Before sending an email to a user via the email_to_user() function, the module should check to see if the config variable $CFG-&amp;gt;emailinterface is enabled. (This is off by default)&lt;br /&gt;
* Assuming the email interface is enabled, the function generate_email_verp_address($moduleid, $payload, $userid) should be called to create an &amp;quot;email session&amp;quot;. The payload should include any data you wish to use in your handling routine - such as the id of the user, or what part of the interface he is interacting with. The function will return a string containing the email session id.&lt;br /&gt;
* Call the email_to_user() function as normal, appending the email session id as the 11th parameter. Keep in mind that you will probably also need to change the text or html of the email to point out that the email interface is active.&lt;br /&gt;
* A function contained in the lib.php file of your module, named [modulename]_process_email($payload, $body) should be written. This is the handler function, which is called when an email reply is received. This function can inspect the contents of the payload received, then parse the email body for data. The $body parameter returns the full email, including the headers.&lt;br /&gt;
&lt;br /&gt;
Note that each email can only be replied to once - the email session is destroyed once an email has been received. If you wish to have multiple replies from a user, you will have to create a new session (and new email) every time. The email session table is also regularly pruned, the default settings allow sessions to persist for one month.&lt;br /&gt;
&lt;br /&gt;
The following utility functions are also defined in admin/process_email.php, which can help:&lt;br /&gt;
* get_email_subject($fullemail) - return the subject of an email&lt;br /&gt;
* strip_email_headers($fullemail) - strip all headers off an email&lt;br /&gt;
* email_is_multipart($fullemail) - determine if an email is a multipart message&lt;br /&gt;
* seperate_multipart($multipartmsg) - seperate a multipart email message into an array of parts, each of which has headers and a body.&lt;br /&gt;
* get_multipart_content_type($part) - determine the content-type of a multipart, generally text/plain or text/html.&lt;br /&gt;
* multipart_is_quoted_printable($part) - determine if a email part has been encoded with the quoted-printable encoding - some email clients tend to do this to html.&lt;br /&gt;
* decode_quoted_printable($partdata) - decode a email that has been encoded with quoted-printable encoding - this needs to be run on the data section of a part (strip_email_headers can be used to seperate the headers of a part).&lt;br /&gt;
* strip_email_reply($body, $ishtml, $identifier) - strip all irrelevant lines of an email message based on a unique identifier embedded within the original message. This is used to determine what is user input, and what is irrelevant data the email client has added.&lt;br /&gt;
* strip_email_reply_multi($body, $ishtml, $identifier) - as above, but allowing for multiple sections of possible user input in a single email message.&lt;br /&gt;
&lt;br /&gt;
Examples of use of these functions can be seen in the handler for the forum module. The idea behind the strip reply functions is that the original email will contain a unique identifier, such as a random 10 character string. This is embedded in a line with instructions for the user to write below and above it, e.g:&lt;br /&gt;
  \/ Please put your response here [ABCDEFGHIJ] \/&lt;br /&gt;
  &amp;lt;User Data&amp;gt;&lt;br /&gt;
  /\ Please put your response here [ABCDEFGHIJ] /\&lt;br /&gt;
This is necessary because of the wide differences between webmail and email clients in handling quotes and prefixing dates/times to replied emails. Keep in mind that text emails have an 80-character line width restrictions, which must also include the quote added by the email client, so any line of a text-email with this identifier should be kept to at least 77 characters to avoid wrapping by an email client. This unique identifier can be easily stored in the payload. Multiple input sections are handled similarly - a number is appended to the end of the identifier, e.g. [ABCDEFGHIJ1] to signfiy the first section of input. The strip_email_reply_multi returns an array containing a map from each numbered section it finds to a string containing all data in that section.&lt;br /&gt;
&lt;br /&gt;
===Developer Info===&lt;br /&gt;
The reply-to header is now encoded in base32 instead of base64 to allow for case-insensitive MTA&#039;s. Generate_email_processing_address was left as a backwards-compatibility wrapper, modules should use generate_email_verp_address now instead.&lt;br /&gt;
&lt;br /&gt;
Email sessions have been created to deal with the lack of space avaliable in the header under base32, payloads are stored in a new table mdl_email_sessions, and are identified with a unique base32 key which is embedded in the reply-to header. Each row has a timestamp, and the table is pruned during cleanup cron in admin/cron.php.&lt;br /&gt;
&lt;br /&gt;
Bounce detection is now linked in with the email interface - bounce detection is included in admin/process_email.php. Some new configuration variables have also been created to help configure these changes - $CFG-&amp;gt;emailinterface and $CFG-&amp;gt;emailsessiontime - and both have been added to the server settings admin page.&lt;br /&gt;
&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27330</id>
		<title>Email processing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27330"/>
		<updated>2007-09-26T18:48:53Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* Email confirmation or registration words */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Features ==&lt;br /&gt;
&lt;br /&gt;
Moodle now makes better use of the SMTP protocol and email in general. Most of the benefits result from using a technique known as Variable Envelope Return Path (VERP).&lt;br /&gt;
&lt;br /&gt;
* Works on most modern MTAs (at least on Unix systems).&lt;br /&gt;
* All processing of bounces and replies is secured using HMAC-MD5-8.&lt;br /&gt;
* Bounces are handled correctly and increase a &amp;quot;bad email&amp;quot; score for the user.&lt;br /&gt;
* noreply@host address is now on Reply-to field, avoiding accidental pollution of users address books.&lt;br /&gt;
* noreply@host has an autorresponder&lt;br /&gt;
* Makes it easy for modules to send emails with a signed VERP reply-to.&lt;br /&gt;
* Handles receving of VERP replies: Validates the HMAC-MD5-8 signature and Dispatches the encoded request data to the relevant module&lt;br /&gt;
&lt;br /&gt;
== Moodle configuration ==&lt;br /&gt;
&lt;br /&gt;
Edit config.php to enable bounce handling, and setup Moodle to match your MTA configuration. Here&#039;s how. Uncomment these lines in config.php (if you cannot find them, copy them from config-dist.php):&lt;br /&gt;
&lt;br /&gt;
  // once handlebounces is true, we will be using VERP for the return address of every sent email&lt;br /&gt;
  $CFG-&amp;gt;handlebounces = true;&lt;br /&gt;
  // minimum bounces allowed per user&lt;br /&gt;
  $CFG-&amp;gt;minbounces = 10;&lt;br /&gt;
  // ratio of bad emails to sent emails&lt;br /&gt;
  // if we get more than 20% bounces &lt;br /&gt;
  // for a given user, his/her email is marked bad&lt;br /&gt;
  $CFG-&amp;gt;bounceratio = .20;&lt;br /&gt;
&lt;br /&gt;
Edit the $CFG-&amp;gt;maildomain line and one of the $CFG-&amp;gt;mailprefix lines (the one that matches your MTA).&lt;br /&gt;
&lt;br /&gt;
Make sure your server has a command-line PHP interpreter, and that it is able to connect to mysql (or postgres if relevant). If you are able to run cron.php from the commandline or from crontab, this means PHP is ok.&lt;br /&gt;
&lt;br /&gt;
Edit the process_email.php script to point to the location of your php binary. It will usually be &#039;&#039;/usr/bin/php&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Email confirmation or registration words==&lt;br /&gt;
*  Students receive a confirmation email when they create a user account.  This text can be found in the lang/?/moodle.php as the emailconfirmation &amp;quot;variable&amp;quot;.&lt;br /&gt;
* Students receive a welcome email when they enroll in a course.  This text can be found in the lang/?/moodle.php file as the welcometocoursetext &amp;quot;variable&amp;quot;.&lt;br /&gt;
*If you feel the need to edit this text, the best way to do this is to go to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit. Once you have done this, hit the &amp;quot;Switch lang directory&amp;quot; button, and do your editing.&lt;br /&gt;
*If you decide to get your hands dirty and work by editing the moodle.php directly, be careful to open the file only in a simple text editor like notepad or wordpad. &lt;br /&gt;
*Tip: Be careful with markup - as you edit, you must use &amp;quot; &amp;quot; for things like putting in hyperlinks, titles and targets. You MUST &#039;escape&#039; them by putting a \ before each &amp;quot;. If you don&#039;t the resulting page will appear blank. For example, to markup a hyperlink:-&lt;br /&gt;
**Use &amp;lt;nowiki&amp;gt;&amp;lt;a href=\&amp;quot;http://www.blah_blah\&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** Do not use &amp;lt;nowiki&amp;gt;&amp;lt;a href=&amp;quot;http://www.blah_blah&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt; &lt;br /&gt;
*Use the \ before each &amp;quot; when marking up things like target=\&amp;quot;_blank&amp;quot; and title=\&amp;quot;Blah blah\&amp;quot; and other similar codes.&lt;br /&gt;
*If you feel you must really go the route of editing the moodle.php file directly, save a copy of the file in its own folder (copy and paste the file in the same folder). That way, if it all goes wrong for you, all you have to do is delete the botched file and rename the &#039;copy of moodle.php&#039; back to &#039;moodle.php&#039; and you are back to square one, no harm done!&lt;br /&gt;
*Having said all that, it is best to do all your editing in the web interface by going to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit.&lt;br /&gt;
&lt;br /&gt;
Make sure &#039;&#039;process_email.php&#039;&#039; is executable by running &amp;quot;chmod ugo+rx process_email.php&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Setup under Postfix ==&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;|&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; and moodle installed under /var/www/moodle we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
== Setup under Qmail ==&lt;br /&gt;
&lt;br /&gt;
Depending on your setup, your aliases will be controlled by one or more of&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;/etc/aliases&#039;&#039;&lt;br /&gt;
* &#039;&#039;/var/qmail/alias/.qmail-PREFIX&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you edit /etc/aliases add a line like this (for a prefix of &#039;mdl&#039;):&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you create /var/qmail/alias/.qmail-PREFIX, just do&lt;br /&gt;
&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-mdl&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-noreply&lt;br /&gt;
&lt;br /&gt;
To this three letter prefix, we will add a &#039;-&#039; when sending and receiving messages. For more info, check out the manpage for dot-qmail.&lt;br /&gt;
&lt;br /&gt;
== Setup under Exim ==&lt;br /&gt;
&lt;br /&gt;
Open &#039;&#039;/etc/exim/exim.conf&#039;&#039; and add to trusted_users the user Apache and cron.php run as (usually &amp;quot;www-data&amp;quot; or &amp;quot;nobody&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;+&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
More documentation about Exim can be found [http://www.exim.org/docs.html here]. You may have to tell Exim not to lowercase the local-part.&lt;br /&gt;
&lt;br /&gt;
== Developer info ==&lt;br /&gt;
&lt;br /&gt;
Changed functions:&lt;br /&gt;
&lt;br /&gt;
* email_to_user() will set the envelope sender to a special bounce processing address (based on $CFG settings)&lt;br /&gt;
* email_to_user() will accept (and set) a reply-to header, to be generated by the module calling the function.&lt;br /&gt;
* associated string changes/additions&lt;br /&gt;
&lt;br /&gt;
New functions:&lt;br /&gt;
&lt;br /&gt;
* generate_email_processing_address() - ALWAYS use this to generate the reply-to header. reply-to header will look like this: (LIMIT: 64 chars total) prefix - EXACTLY four chars encodeded, packed, moduleid (0 for core) (2 chars) up to 42 chars for the modules to put anything they want it (can contain userid (or, eg for forum, postids to reply to), or anything really. 42 chars is ABSOLUTE LIMIT) 16 char hash (half an md5) of the first part of the address, together with a site &amp;quot;secret&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* moodle_process_email() - any non-module email processing goes here (currently used for processing bounces)&lt;br /&gt;
&lt;br /&gt;
New files:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/process_email.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This script needs to be called from your MTA for anything starting with the 3 char prefix described above (and optionally, the noreply address).&lt;br /&gt;
&lt;br /&gt;
How does it work? It will break down and unencode the email address into moduleid and validate the half md5 hash, and call $modname_process_email (if it exists). Arguments to these functions are: $modargs (any part of the email address that isn&#039;t the prefix, modid or the hash) and the contents of the email (read from STDIN).&lt;br /&gt;
&lt;br /&gt;
It doubles up as the noreplyaddress autorresponder if you configure it with that address as well. Replying with a friendly &amp;quot;this is not a real email address&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
== Module Authors ==&lt;br /&gt;
&lt;br /&gt;
Take a look at new functions moodle_process_email() and generate_email_processing_address() in moodlelib.php for ideas about how to&lt;br /&gt;
&lt;br /&gt;
* encode and unencode the arguments your module needs to do the processing&lt;br /&gt;
* how to deal with multiple &amp;quot;actions&amp;quot; for any given module.&lt;br /&gt;
&lt;br /&gt;
In a nutshell, users can send emails to Moodle using special dynamic addresses. These emails can trigger a call to a module function in the form of modulename_process_email($str, $bodyofemail). The $str part will be up to 42 characters of data generated by Moodle (presumably by your own module), and the $bodyofemailpart is the contents of the email (got by reading STDIN - usually generated by the users MUA).&lt;br /&gt;
&lt;br /&gt;
The 42 characters come from the &amp;quot;local part&amp;quot; of an email address (the part before the @ sign) which can have up to 64 chars. Out of those 64 chars, Moodle uses 22 characters, leaving you with 42 characters to encode data.&lt;br /&gt;
&lt;br /&gt;
What do we do with the 22 chars? Four go to the prefix, which we need to let the MTA know to pass the message to our script. Two go to identify the module ID so we know which module has generated the message (and so we dispatch the request to that module). The remaining 16 are a signature (HMAC-MD5-8) we use to authenticate the message.&lt;br /&gt;
&lt;br /&gt;
Forty-two characters isn&#039;t a lot (although it could be the answer to life, the universe, and everything!) so make sure you use those characters wisely.&lt;br /&gt;
&lt;br /&gt;
The most efficient way to encode database IDs in their full range (so that they can be placed in an email address) we have found is base64_encode(pack(&#039;V&#039;,2147483647)), which returns &amp;quot;/ / / / f w = =&amp;quot;. The two trailing &amp;quot;= =&amp;quot; are redundant and you can remove them (you&#039;ll need to reappend them when retrieving your data). Join your parameters as encoded IDs in positional slots for efficiency.&lt;br /&gt;
&lt;br /&gt;
To retrieve your data, use substr() to separate your parameters, and then unpack(&#039;V&#039;,base64_decode($str)). Note that it&#039;ll return a one-element array.&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Using &#039;V&#039; reaches 2147483647, half the range of mySQL&#039;s INT. Additionally, &#039;V&#039; behaves like a signed value, rather than an unsigned, so I suspect there&#039;s a bug in PHP&#039;s documentation of pack().&lt;br /&gt;
&lt;br /&gt;
With each ID taking 6-chars (8 chars if we find a way to use the full range of &#039;V&#039;), you have a limited number of parameters. If you need to encode more information, store it in the DB and send emails that point to your stored data. Remember to cleanup this temporary data after a safe period of time.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Do not try to use variable-width encoding to put IDs, as it&#039;ll work in small installations and break in larger ones.&lt;br /&gt;
&lt;br /&gt;
== Security issues ==&lt;br /&gt;
&lt;br /&gt;
Any code in modulename_process_email() _must_ assume it will see repeat replies and handle them gracefully. The definition of &#039;gracefully&#039; depends on what the code does.&lt;br /&gt;
&lt;br /&gt;
Email servers (MTAs) will sometimes re-transmit a message if they are unsure that the receiving MTA got it -- and sysadmins may sometimes replay a whole email queue if something&#039;s gone wrong. In that case, they email body will be identical, the headers slightly different.&lt;br /&gt;
&lt;br /&gt;
In a different case, the user may &#039;reply&#039; to the message twice. Perhaps in error, perhaps purposefully. What to do depends on the specific scenario.&lt;br /&gt;
&lt;br /&gt;
We /could/ support better protection at the framework level, by keeping track of every reply-to address we send out. We decided against that because (a) the performance impact will be important (b) we want the 1st cut to be lightweight and simple to change in case we need to.&lt;br /&gt;
&lt;br /&gt;
With this the initial implementation, modules should expose functions that handle these &amp;quot;replay&amp;quot; cases correctly. If later we want to expose additional functions, we can add such tracking as an optional thing. It&#039;d be awful to have it across all emails sent from Moodle.&lt;br /&gt;
&lt;br /&gt;
== Experimental email processing, pending merge into 1.9/2.0 ==&lt;br /&gt;
===Module Authors===&lt;br /&gt;
The email interface allows you to let users respond to emails sent via your module and affect change in them. The basic idea is that each email is uniquely identified with an email session that carries with it a simple payload. This payload is stored via database, and cannot be changed by the user. Replies are handled by module code in your lib.php library - modulename_process_email($payload, $body) - which is passed the session payload and the body (with full headers) of the email received, to be parsed as you like. Some utility functions are available as well to help with this.&lt;br /&gt;
&lt;br /&gt;
Here is an outline of the intended use:&lt;br /&gt;
* Before sending an email to a user via the email_to_user() function, the module should check to see if the config variable $CFG-&amp;gt;emailinterface is enabled. (This is off by default)&lt;br /&gt;
* Assuming the email interface is enabled, the function generate_email_verp_address($moduleid, $payload, $userid) should be called to create an &amp;quot;email session&amp;quot;. The payload should include any data you wish to use in your handling routine - such as the id of the user, or what part of the interface he is interacting with. The function will return a string containing the email session id.&lt;br /&gt;
* Call the email_to_user() function as normal, appending the email session id as the 11th parameter. Keep in mind that you will probably also need to change the text or html of the email to point out that the email interface is active.&lt;br /&gt;
* A function contained in the lib.php file of your module, named [modulename]_process_email($payload, $body) should be written. This is the handler function, which is called when an email reply is received. This function can inspect the contents of the payload received, then parse the email body for data. The $body parameter returns the full email, including the headers.&lt;br /&gt;
&lt;br /&gt;
Note that each email can only be replied to once - the email session is destroyed once an email has been received. If you wish to have multiple replies from a user, you will have to create a new session (and new email) every time. The email session table is also regularly pruned, the default settings allow sessions to persist for one month.&lt;br /&gt;
&lt;br /&gt;
The following utility functions are also defined in admin/process_email.php, which can help:&lt;br /&gt;
* get_email_subject($fullemail) - return the subject of an email&lt;br /&gt;
* strip_email_headers($fullemail) - strip all headers off an email&lt;br /&gt;
* email_is_multipart($fullemail) - determine if an email is a multipart message&lt;br /&gt;
* seperate_multipart($multipartmsg) - seperate a multipart email message into an array of parts, each of which has headers and a body.&lt;br /&gt;
* get_multipart_content_type($part) - determine the content-type of a multipart, generally text/plain or text/html.&lt;br /&gt;
* multipart_is_quoted_printable($part) - determine if a email part has been encoded with the quoted-printable encoding - some email clients tend to do this to html.&lt;br /&gt;
* decode_quoted_printable($partdata) - decode a email that has been encoded with quoted-printable encoding - this needs to be run on the data section of a part (strip_email_headers can be used to seperate the headers of a part).&lt;br /&gt;
* strip_email_reply($body, $ishtml, $identifier) - strip all irrelevant lines of an email message based on a unique identifier embedded within the original message. This is used to determine what is user input, and what is irrelevant data the email client has added.&lt;br /&gt;
* strip_email_reply_multi($body, $ishtml, $identifier) - as above, but allowing for multiple sections of possible user input in a single email message.&lt;br /&gt;
&lt;br /&gt;
Examples of use of these functions can be seen in the handler for the forum module. The idea behind the strip reply functions is that the original email will contain a unique identifier, such as a random 10 character string. This is embedded in a line with instructions for the user to write below and above it, e.g:&lt;br /&gt;
  \/ Please put your response here [ABCDEFGHIJ] \/&lt;br /&gt;
  &amp;lt;User Data&amp;gt;&lt;br /&gt;
  /\ Please put your response here [ABCDEFGHIJ] /\&lt;br /&gt;
This is necessary because of the wide differences between webmail and email clients in handling quotes and prefixing dates/times to replied emails. Keep in mind that text emails have an 80-character line width restrictions, which must also include the quote added by the email client, so any line of a text-email with this identifier should be kept to at least 77 characters to avoid wrapping by an email client. This unique identifier can be easily stored in the payload. Multiple input sections are handled similarly - a number is appended to the end of the identifier, e.g. [ABCDEFGHIJ1] to signfiy the first section of input. The strip_email_reply_multi returns an array containing a map from each numbered section it finds to a string containing all data in that section.&lt;br /&gt;
&lt;br /&gt;
===Developer Info===&lt;br /&gt;
The reply-to header is now encoded in base32 instead of base64 to allow for case-insensitive MTA&#039;s. Generate_email_processing_address was left as a backwards-compatibility wrapper, modules should use generate_email_verp_address now instead.&lt;br /&gt;
&lt;br /&gt;
Email sessions have been created to deal with the lack of space avaliable in the header under base32, payloads are stored in a new table mdl_email_sessions, and are identified with a unique base32 key which is embedded in the reply-to header. Each row has a timestamp, and the table is pruned during cleanup cron in admin/cron.php.&lt;br /&gt;
&lt;br /&gt;
Bounce detection is now linked in with the email interface - bounce detection is included in admin/process_email.php. Some new configuration variables have also been created to help configure these changes - $CFG-&amp;gt;emailinterface and $CFG-&amp;gt;emailsessiontime - and both have been added to the server settings admin page.&lt;br /&gt;
&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27329</id>
		<title>Email processing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27329"/>
		<updated>2007-09-26T18:47:33Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* Email confirmation or registration words */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Features ==&lt;br /&gt;
&lt;br /&gt;
Moodle now makes better use of the SMTP protocol and email in general. Most of the benefits result from using a technique known as Variable Envelope Return Path (VERP).&lt;br /&gt;
&lt;br /&gt;
* Works on most modern MTAs (at least on Unix systems).&lt;br /&gt;
* All processing of bounces and replies is secured using HMAC-MD5-8.&lt;br /&gt;
* Bounces are handled correctly and increase a &amp;quot;bad email&amp;quot; score for the user.&lt;br /&gt;
* noreply@host address is now on Reply-to field, avoiding accidental pollution of users address books.&lt;br /&gt;
* noreply@host has an autorresponder&lt;br /&gt;
* Makes it easy for modules to send emails with a signed VERP reply-to.&lt;br /&gt;
* Handles receving of VERP replies: Validates the HMAC-MD5-8 signature and Dispatches the encoded request data to the relevant module&lt;br /&gt;
&lt;br /&gt;
== Moodle configuration ==&lt;br /&gt;
&lt;br /&gt;
Edit config.php to enable bounce handling, and setup Moodle to match your MTA configuration. Here&#039;s how. Uncomment these lines in config.php (if you cannot find them, copy them from config-dist.php):&lt;br /&gt;
&lt;br /&gt;
  // once handlebounces is true, we will be using VERP for the return address of every sent email&lt;br /&gt;
  $CFG-&amp;gt;handlebounces = true;&lt;br /&gt;
  // minimum bounces allowed per user&lt;br /&gt;
  $CFG-&amp;gt;minbounces = 10;&lt;br /&gt;
  // ratio of bad emails to sent emails&lt;br /&gt;
  // if we get more than 20% bounces &lt;br /&gt;
  // for a given user, his/her email is marked bad&lt;br /&gt;
  $CFG-&amp;gt;bounceratio = .20;&lt;br /&gt;
&lt;br /&gt;
Edit the $CFG-&amp;gt;maildomain line and one of the $CFG-&amp;gt;mailprefix lines (the one that matches your MTA).&lt;br /&gt;
&lt;br /&gt;
Make sure your server has a command-line PHP interpreter, and that it is able to connect to mysql (or postgres if relevant). If you are able to run cron.php from the commandline or from crontab, this means PHP is ok.&lt;br /&gt;
&lt;br /&gt;
Edit the process_email.php script to point to the location of your php binary. It will usually be &#039;&#039;/usr/bin/php&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Email confirmation or registration words==&lt;br /&gt;
*  Students receive a confirmation email when they create a user account.  This text can be found in the lang/?/moodle.php as the emailconfirmation &amp;quot;variable&amp;quot;.&lt;br /&gt;
* Students receive a welcome email when they enroll in a course.  This text can be found in the lang/?/moodle.php file as the welcometocoursetext &amp;quot;variable&amp;quot;.&lt;br /&gt;
*If you feel the need to edit this text, the best way to do this is to go to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit. Once you have done this, hit the &amp;quot;Switch lang directory&amp;quot; button, and do your editing.&lt;br /&gt;
*If you decide to get your hands dirty and work by editing the moodle.php directly, be careful to open the file only in a simple text editor like notepad or wordpad. &lt;br /&gt;
*Tip: Be careful with markup - as you edit, you must use &amp;quot; &amp;quot; for things like putting in hyperlinks, titles and targets. You MUST &#039;escape&#039; them by putting a \ before each &amp;quot;. If you don&#039;t the resulting page will appear blank. For example, to markup a hyperlink:-&lt;br /&gt;
**Use &amp;lt;nowiki&amp;gt;&amp;lt;a href=\&amp;quot;http://www.blah_blah\&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** Do not use &amp;lt;nowiki&amp;gt;&amp;lt;a href=&amp;quot;http://www.blah_blah&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt; &lt;br /&gt;
*Use the \ before each &amp;quot; when marking up things like target=\&amp;quot;_blank&amp;quot; and title=\&amp;quot;Blah blah\&amp;quot; and other similar codes, anywhere you must use &amp;quot; in the markup.&lt;br /&gt;
*If you feel you must really go the route of editing the moodle.php file directly, save a copy of the file in its own folder (copy and paste the file in the same folder). That way, if it all goes wrong for you, all you have to do is delete the botched file and rename the &#039;copy of moodle.php&#039; back to &#039;moodle.php&#039; and you are back to square one, no harm done!&lt;br /&gt;
*Having said all that, it is best to do all your editing in the web interface by going to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit.&lt;br /&gt;
&lt;br /&gt;
Make sure &#039;&#039;process_email.php&#039;&#039; is executable by running &amp;quot;chmod ugo+rx process_email.php&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Setup under Postfix ==&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;|&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; and moodle installed under /var/www/moodle we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
== Setup under Qmail ==&lt;br /&gt;
&lt;br /&gt;
Depending on your setup, your aliases will be controlled by one or more of&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;/etc/aliases&#039;&#039;&lt;br /&gt;
* &#039;&#039;/var/qmail/alias/.qmail-PREFIX&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you edit /etc/aliases add a line like this (for a prefix of &#039;mdl&#039;):&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you create /var/qmail/alias/.qmail-PREFIX, just do&lt;br /&gt;
&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-mdl&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-noreply&lt;br /&gt;
&lt;br /&gt;
To this three letter prefix, we will add a &#039;-&#039; when sending and receiving messages. For more info, check out the manpage for dot-qmail.&lt;br /&gt;
&lt;br /&gt;
== Setup under Exim ==&lt;br /&gt;
&lt;br /&gt;
Open &#039;&#039;/etc/exim/exim.conf&#039;&#039; and add to trusted_users the user Apache and cron.php run as (usually &amp;quot;www-data&amp;quot; or &amp;quot;nobody&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;+&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
More documentation about Exim can be found [http://www.exim.org/docs.html here]. You may have to tell Exim not to lowercase the local-part.&lt;br /&gt;
&lt;br /&gt;
== Developer info ==&lt;br /&gt;
&lt;br /&gt;
Changed functions:&lt;br /&gt;
&lt;br /&gt;
* email_to_user() will set the envelope sender to a special bounce processing address (based on $CFG settings)&lt;br /&gt;
* email_to_user() will accept (and set) a reply-to header, to be generated by the module calling the function.&lt;br /&gt;
* associated string changes/additions&lt;br /&gt;
&lt;br /&gt;
New functions:&lt;br /&gt;
&lt;br /&gt;
* generate_email_processing_address() - ALWAYS use this to generate the reply-to header. reply-to header will look like this: (LIMIT: 64 chars total) prefix - EXACTLY four chars encodeded, packed, moduleid (0 for core) (2 chars) up to 42 chars for the modules to put anything they want it (can contain userid (or, eg for forum, postids to reply to), or anything really. 42 chars is ABSOLUTE LIMIT) 16 char hash (half an md5) of the first part of the address, together with a site &amp;quot;secret&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* moodle_process_email() - any non-module email processing goes here (currently used for processing bounces)&lt;br /&gt;
&lt;br /&gt;
New files:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/process_email.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This script needs to be called from your MTA for anything starting with the 3 char prefix described above (and optionally, the noreply address).&lt;br /&gt;
&lt;br /&gt;
How does it work? It will break down and unencode the email address into moduleid and validate the half md5 hash, and call $modname_process_email (if it exists). Arguments to these functions are: $modargs (any part of the email address that isn&#039;t the prefix, modid or the hash) and the contents of the email (read from STDIN).&lt;br /&gt;
&lt;br /&gt;
It doubles up as the noreplyaddress autorresponder if you configure it with that address as well. Replying with a friendly &amp;quot;this is not a real email address&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
== Module Authors ==&lt;br /&gt;
&lt;br /&gt;
Take a look at new functions moodle_process_email() and generate_email_processing_address() in moodlelib.php for ideas about how to&lt;br /&gt;
&lt;br /&gt;
* encode and unencode the arguments your module needs to do the processing&lt;br /&gt;
* how to deal with multiple &amp;quot;actions&amp;quot; for any given module.&lt;br /&gt;
&lt;br /&gt;
In a nutshell, users can send emails to Moodle using special dynamic addresses. These emails can trigger a call to a module function in the form of modulename_process_email($str, $bodyofemail). The $str part will be up to 42 characters of data generated by Moodle (presumably by your own module), and the $bodyofemailpart is the contents of the email (got by reading STDIN - usually generated by the users MUA).&lt;br /&gt;
&lt;br /&gt;
The 42 characters come from the &amp;quot;local part&amp;quot; of an email address (the part before the @ sign) which can have up to 64 chars. Out of those 64 chars, Moodle uses 22 characters, leaving you with 42 characters to encode data.&lt;br /&gt;
&lt;br /&gt;
What do we do with the 22 chars? Four go to the prefix, which we need to let the MTA know to pass the message to our script. Two go to identify the module ID so we know which module has generated the message (and so we dispatch the request to that module). The remaining 16 are a signature (HMAC-MD5-8) we use to authenticate the message.&lt;br /&gt;
&lt;br /&gt;
Forty-two characters isn&#039;t a lot (although it could be the answer to life, the universe, and everything!) so make sure you use those characters wisely.&lt;br /&gt;
&lt;br /&gt;
The most efficient way to encode database IDs in their full range (so that they can be placed in an email address) we have found is base64_encode(pack(&#039;V&#039;,2147483647)), which returns &amp;quot;/ / / / f w = =&amp;quot;. The two trailing &amp;quot;= =&amp;quot; are redundant and you can remove them (you&#039;ll need to reappend them when retrieving your data). Join your parameters as encoded IDs in positional slots for efficiency.&lt;br /&gt;
&lt;br /&gt;
To retrieve your data, use substr() to separate your parameters, and then unpack(&#039;V&#039;,base64_decode($str)). Note that it&#039;ll return a one-element array.&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Using &#039;V&#039; reaches 2147483647, half the range of mySQL&#039;s INT. Additionally, &#039;V&#039; behaves like a signed value, rather than an unsigned, so I suspect there&#039;s a bug in PHP&#039;s documentation of pack().&lt;br /&gt;
&lt;br /&gt;
With each ID taking 6-chars (8 chars if we find a way to use the full range of &#039;V&#039;), you have a limited number of parameters. If you need to encode more information, store it in the DB and send emails that point to your stored data. Remember to cleanup this temporary data after a safe period of time.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Do not try to use variable-width encoding to put IDs, as it&#039;ll work in small installations and break in larger ones.&lt;br /&gt;
&lt;br /&gt;
== Security issues ==&lt;br /&gt;
&lt;br /&gt;
Any code in modulename_process_email() _must_ assume it will see repeat replies and handle them gracefully. The definition of &#039;gracefully&#039; depends on what the code does.&lt;br /&gt;
&lt;br /&gt;
Email servers (MTAs) will sometimes re-transmit a message if they are unsure that the receiving MTA got it -- and sysadmins may sometimes replay a whole email queue if something&#039;s gone wrong. In that case, they email body will be identical, the headers slightly different.&lt;br /&gt;
&lt;br /&gt;
In a different case, the user may &#039;reply&#039; to the message twice. Perhaps in error, perhaps purposefully. What to do depends on the specific scenario.&lt;br /&gt;
&lt;br /&gt;
We /could/ support better protection at the framework level, by keeping track of every reply-to address we send out. We decided against that because (a) the performance impact will be important (b) we want the 1st cut to be lightweight and simple to change in case we need to.&lt;br /&gt;
&lt;br /&gt;
With this the initial implementation, modules should expose functions that handle these &amp;quot;replay&amp;quot; cases correctly. If later we want to expose additional functions, we can add such tracking as an optional thing. It&#039;d be awful to have it across all emails sent from Moodle.&lt;br /&gt;
&lt;br /&gt;
== Experimental email processing, pending merge into 1.9/2.0 ==&lt;br /&gt;
===Module Authors===&lt;br /&gt;
The email interface allows you to let users respond to emails sent via your module and affect change in them. The basic idea is that each email is uniquely identified with an email session that carries with it a simple payload. This payload is stored via database, and cannot be changed by the user. Replies are handled by module code in your lib.php library - modulename_process_email($payload, $body) - which is passed the session payload and the body (with full headers) of the email received, to be parsed as you like. Some utility functions are available as well to help with this.&lt;br /&gt;
&lt;br /&gt;
Here is an outline of the intended use:&lt;br /&gt;
* Before sending an email to a user via the email_to_user() function, the module should check to see if the config variable $CFG-&amp;gt;emailinterface is enabled. (This is off by default)&lt;br /&gt;
* Assuming the email interface is enabled, the function generate_email_verp_address($moduleid, $payload, $userid) should be called to create an &amp;quot;email session&amp;quot;. The payload should include any data you wish to use in your handling routine - such as the id of the user, or what part of the interface he is interacting with. The function will return a string containing the email session id.&lt;br /&gt;
* Call the email_to_user() function as normal, appending the email session id as the 11th parameter. Keep in mind that you will probably also need to change the text or html of the email to point out that the email interface is active.&lt;br /&gt;
* A function contained in the lib.php file of your module, named [modulename]_process_email($payload, $body) should be written. This is the handler function, which is called when an email reply is received. This function can inspect the contents of the payload received, then parse the email body for data. The $body parameter returns the full email, including the headers.&lt;br /&gt;
&lt;br /&gt;
Note that each email can only be replied to once - the email session is destroyed once an email has been received. If you wish to have multiple replies from a user, you will have to create a new session (and new email) every time. The email session table is also regularly pruned, the default settings allow sessions to persist for one month.&lt;br /&gt;
&lt;br /&gt;
The following utility functions are also defined in admin/process_email.php, which can help:&lt;br /&gt;
* get_email_subject($fullemail) - return the subject of an email&lt;br /&gt;
* strip_email_headers($fullemail) - strip all headers off an email&lt;br /&gt;
* email_is_multipart($fullemail) - determine if an email is a multipart message&lt;br /&gt;
* seperate_multipart($multipartmsg) - seperate a multipart email message into an array of parts, each of which has headers and a body.&lt;br /&gt;
* get_multipart_content_type($part) - determine the content-type of a multipart, generally text/plain or text/html.&lt;br /&gt;
* multipart_is_quoted_printable($part) - determine if a email part has been encoded with the quoted-printable encoding - some email clients tend to do this to html.&lt;br /&gt;
* decode_quoted_printable($partdata) - decode a email that has been encoded with quoted-printable encoding - this needs to be run on the data section of a part (strip_email_headers can be used to seperate the headers of a part).&lt;br /&gt;
* strip_email_reply($body, $ishtml, $identifier) - strip all irrelevant lines of an email message based on a unique identifier embedded within the original message. This is used to determine what is user input, and what is irrelevant data the email client has added.&lt;br /&gt;
* strip_email_reply_multi($body, $ishtml, $identifier) - as above, but allowing for multiple sections of possible user input in a single email message.&lt;br /&gt;
&lt;br /&gt;
Examples of use of these functions can be seen in the handler for the forum module. The idea behind the strip reply functions is that the original email will contain a unique identifier, such as a random 10 character string. This is embedded in a line with instructions for the user to write below and above it, e.g:&lt;br /&gt;
  \/ Please put your response here [ABCDEFGHIJ] \/&lt;br /&gt;
  &amp;lt;User Data&amp;gt;&lt;br /&gt;
  /\ Please put your response here [ABCDEFGHIJ] /\&lt;br /&gt;
This is necessary because of the wide differences between webmail and email clients in handling quotes and prefixing dates/times to replied emails. Keep in mind that text emails have an 80-character line width restrictions, which must also include the quote added by the email client, so any line of a text-email with this identifier should be kept to at least 77 characters to avoid wrapping by an email client. This unique identifier can be easily stored in the payload. Multiple input sections are handled similarly - a number is appended to the end of the identifier, e.g. [ABCDEFGHIJ1] to signfiy the first section of input. The strip_email_reply_multi returns an array containing a map from each numbered section it finds to a string containing all data in that section.&lt;br /&gt;
&lt;br /&gt;
===Developer Info===&lt;br /&gt;
The reply-to header is now encoded in base32 instead of base64 to allow for case-insensitive MTA&#039;s. Generate_email_processing_address was left as a backwards-compatibility wrapper, modules should use generate_email_verp_address now instead.&lt;br /&gt;
&lt;br /&gt;
Email sessions have been created to deal with the lack of space avaliable in the header under base32, payloads are stored in a new table mdl_email_sessions, and are identified with a unique base32 key which is embedded in the reply-to header. Each row has a timestamp, and the table is pruned during cleanup cron in admin/cron.php.&lt;br /&gt;
&lt;br /&gt;
Bounce detection is now linked in with the email interface - bounce detection is included in admin/process_email.php. Some new configuration variables have also been created to help configure these changes - $CFG-&amp;gt;emailinterface and $CFG-&amp;gt;emailsessiontime - and both have been added to the server settings admin page.&lt;br /&gt;
&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27328</id>
		<title>Email processing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27328"/>
		<updated>2007-09-26T18:45:27Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* Email confirmation or registration words */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Features ==&lt;br /&gt;
&lt;br /&gt;
Moodle now makes better use of the SMTP protocol and email in general. Most of the benefits result from using a technique known as Variable Envelope Return Path (VERP).&lt;br /&gt;
&lt;br /&gt;
* Works on most modern MTAs (at least on Unix systems).&lt;br /&gt;
* All processing of bounces and replies is secured using HMAC-MD5-8.&lt;br /&gt;
* Bounces are handled correctly and increase a &amp;quot;bad email&amp;quot; score for the user.&lt;br /&gt;
* noreply@host address is now on Reply-to field, avoiding accidental pollution of users address books.&lt;br /&gt;
* noreply@host has an autorresponder&lt;br /&gt;
* Makes it easy for modules to send emails with a signed VERP reply-to.&lt;br /&gt;
* Handles receving of VERP replies: Validates the HMAC-MD5-8 signature and Dispatches the encoded request data to the relevant module&lt;br /&gt;
&lt;br /&gt;
== Moodle configuration ==&lt;br /&gt;
&lt;br /&gt;
Edit config.php to enable bounce handling, and setup Moodle to match your MTA configuration. Here&#039;s how. Uncomment these lines in config.php (if you cannot find them, copy them from config-dist.php):&lt;br /&gt;
&lt;br /&gt;
  // once handlebounces is true, we will be using VERP for the return address of every sent email&lt;br /&gt;
  $CFG-&amp;gt;handlebounces = true;&lt;br /&gt;
  // minimum bounces allowed per user&lt;br /&gt;
  $CFG-&amp;gt;minbounces = 10;&lt;br /&gt;
  // ratio of bad emails to sent emails&lt;br /&gt;
  // if we get more than 20% bounces &lt;br /&gt;
  // for a given user, his/her email is marked bad&lt;br /&gt;
  $CFG-&amp;gt;bounceratio = .20;&lt;br /&gt;
&lt;br /&gt;
Edit the $CFG-&amp;gt;maildomain line and one of the $CFG-&amp;gt;mailprefix lines (the one that matches your MTA).&lt;br /&gt;
&lt;br /&gt;
Make sure your server has a command-line PHP interpreter, and that it is able to connect to mysql (or postgres if relevant). If you are able to run cron.php from the commandline or from crontab, this means PHP is ok.&lt;br /&gt;
&lt;br /&gt;
Edit the process_email.php script to point to the location of your php binary. It will usually be &#039;&#039;/usr/bin/php&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Email confirmation or registration words==&lt;br /&gt;
*  Students receive a confirmation email when they create a user account.  This text can be found in the lang/?/moodle.php as the emailconfirmation &amp;quot;variable&amp;quot;.&lt;br /&gt;
* Students receive a welcome email when they enroll in a course.  This text can be found in the lang/?/moodle.php file as the welcometocoursetext &amp;quot;variable&amp;quot;.&lt;br /&gt;
*If you feel the need to edit this text, the best way to do this is to go to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit. Once you have done this, hit the &amp;quot;Switch lang directory&amp;quot; button, and do your editing.&lt;br /&gt;
*If you decide to get your hands dirty and work by editing the moodle.php directly, be careful to open the file only in a simple text editor like notepad or wordpad. &lt;br /&gt;
*Tip: Be careful with markup - as you edit, you must use &amp;quot; &amp;quot; for things like putting in hyperlinks, titles and targets. You MUST &#039;escape&#039; them by putting a \ before each &amp;quot;. If you don&#039;t the resulting page will appear blank. For example, to markup a hyperlink:-&lt;br /&gt;
**Use &amp;lt;nowiki&amp;gt;&amp;lt;a href=\&amp;quot;http://www.blah_blah\&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** Do not use &amp;lt;nowiki&amp;gt;&amp;lt;a href=&amp;quot;http://www.blah_blah&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt; &lt;br /&gt;
**Use the \ before target= and title= and other similar codes, anywhere you must use &amp;quot; in the markup.&lt;br /&gt;
*If you feel you must really go the route of editing the moodle.php file directly, save a copy of the file in its own folder (copy and paste the file in the same folder). That way, if it all goes wrong for you, all you have to do is delete the botched file and rename the &#039;copy of moodle.php&#039; back to &#039;moodle.php&#039; and you are back to square one, no harm done!&lt;br /&gt;
*Having said all that, it is best to do all your editing in the web interface by going to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit.&lt;br /&gt;
&lt;br /&gt;
Make sure &#039;&#039;process_email.php&#039;&#039; is executable by running &amp;quot;chmod ugo+rx process_email.php&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Setup under Postfix ==&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;|&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; and moodle installed under /var/www/moodle we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
== Setup under Qmail ==&lt;br /&gt;
&lt;br /&gt;
Depending on your setup, your aliases will be controlled by one or more of&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;/etc/aliases&#039;&#039;&lt;br /&gt;
* &#039;&#039;/var/qmail/alias/.qmail-PREFIX&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you edit /etc/aliases add a line like this (for a prefix of &#039;mdl&#039;):&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you create /var/qmail/alias/.qmail-PREFIX, just do&lt;br /&gt;
&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-mdl&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-noreply&lt;br /&gt;
&lt;br /&gt;
To this three letter prefix, we will add a &#039;-&#039; when sending and receiving messages. For more info, check out the manpage for dot-qmail.&lt;br /&gt;
&lt;br /&gt;
== Setup under Exim ==&lt;br /&gt;
&lt;br /&gt;
Open &#039;&#039;/etc/exim/exim.conf&#039;&#039; and add to trusted_users the user Apache and cron.php run as (usually &amp;quot;www-data&amp;quot; or &amp;quot;nobody&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;+&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
More documentation about Exim can be found [http://www.exim.org/docs.html here]. You may have to tell Exim not to lowercase the local-part.&lt;br /&gt;
&lt;br /&gt;
== Developer info ==&lt;br /&gt;
&lt;br /&gt;
Changed functions:&lt;br /&gt;
&lt;br /&gt;
* email_to_user() will set the envelope sender to a special bounce processing address (based on $CFG settings)&lt;br /&gt;
* email_to_user() will accept (and set) a reply-to header, to be generated by the module calling the function.&lt;br /&gt;
* associated string changes/additions&lt;br /&gt;
&lt;br /&gt;
New functions:&lt;br /&gt;
&lt;br /&gt;
* generate_email_processing_address() - ALWAYS use this to generate the reply-to header. reply-to header will look like this: (LIMIT: 64 chars total) prefix - EXACTLY four chars encodeded, packed, moduleid (0 for core) (2 chars) up to 42 chars for the modules to put anything they want it (can contain userid (or, eg for forum, postids to reply to), or anything really. 42 chars is ABSOLUTE LIMIT) 16 char hash (half an md5) of the first part of the address, together with a site &amp;quot;secret&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* moodle_process_email() - any non-module email processing goes here (currently used for processing bounces)&lt;br /&gt;
&lt;br /&gt;
New files:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/process_email.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This script needs to be called from your MTA for anything starting with the 3 char prefix described above (and optionally, the noreply address).&lt;br /&gt;
&lt;br /&gt;
How does it work? It will break down and unencode the email address into moduleid and validate the half md5 hash, and call $modname_process_email (if it exists). Arguments to these functions are: $modargs (any part of the email address that isn&#039;t the prefix, modid or the hash) and the contents of the email (read from STDIN).&lt;br /&gt;
&lt;br /&gt;
It doubles up as the noreplyaddress autorresponder if you configure it with that address as well. Replying with a friendly &amp;quot;this is not a real email address&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
== Module Authors ==&lt;br /&gt;
&lt;br /&gt;
Take a look at new functions moodle_process_email() and generate_email_processing_address() in moodlelib.php for ideas about how to&lt;br /&gt;
&lt;br /&gt;
* encode and unencode the arguments your module needs to do the processing&lt;br /&gt;
* how to deal with multiple &amp;quot;actions&amp;quot; for any given module.&lt;br /&gt;
&lt;br /&gt;
In a nutshell, users can send emails to Moodle using special dynamic addresses. These emails can trigger a call to a module function in the form of modulename_process_email($str, $bodyofemail). The $str part will be up to 42 characters of data generated by Moodle (presumably by your own module), and the $bodyofemailpart is the contents of the email (got by reading STDIN - usually generated by the users MUA).&lt;br /&gt;
&lt;br /&gt;
The 42 characters come from the &amp;quot;local part&amp;quot; of an email address (the part before the @ sign) which can have up to 64 chars. Out of those 64 chars, Moodle uses 22 characters, leaving you with 42 characters to encode data.&lt;br /&gt;
&lt;br /&gt;
What do we do with the 22 chars? Four go to the prefix, which we need to let the MTA know to pass the message to our script. Two go to identify the module ID so we know which module has generated the message (and so we dispatch the request to that module). The remaining 16 are a signature (HMAC-MD5-8) we use to authenticate the message.&lt;br /&gt;
&lt;br /&gt;
Forty-two characters isn&#039;t a lot (although it could be the answer to life, the universe, and everything!) so make sure you use those characters wisely.&lt;br /&gt;
&lt;br /&gt;
The most efficient way to encode database IDs in their full range (so that they can be placed in an email address) we have found is base64_encode(pack(&#039;V&#039;,2147483647)), which returns &amp;quot;/ / / / f w = =&amp;quot;. The two trailing &amp;quot;= =&amp;quot; are redundant and you can remove them (you&#039;ll need to reappend them when retrieving your data). Join your parameters as encoded IDs in positional slots for efficiency.&lt;br /&gt;
&lt;br /&gt;
To retrieve your data, use substr() to separate your parameters, and then unpack(&#039;V&#039;,base64_decode($str)). Note that it&#039;ll return a one-element array.&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Using &#039;V&#039; reaches 2147483647, half the range of mySQL&#039;s INT. Additionally, &#039;V&#039; behaves like a signed value, rather than an unsigned, so I suspect there&#039;s a bug in PHP&#039;s documentation of pack().&lt;br /&gt;
&lt;br /&gt;
With each ID taking 6-chars (8 chars if we find a way to use the full range of &#039;V&#039;), you have a limited number of parameters. If you need to encode more information, store it in the DB and send emails that point to your stored data. Remember to cleanup this temporary data after a safe period of time.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Do not try to use variable-width encoding to put IDs, as it&#039;ll work in small installations and break in larger ones.&lt;br /&gt;
&lt;br /&gt;
== Security issues ==&lt;br /&gt;
&lt;br /&gt;
Any code in modulename_process_email() _must_ assume it will see repeat replies and handle them gracefully. The definition of &#039;gracefully&#039; depends on what the code does.&lt;br /&gt;
&lt;br /&gt;
Email servers (MTAs) will sometimes re-transmit a message if they are unsure that the receiving MTA got it -- and sysadmins may sometimes replay a whole email queue if something&#039;s gone wrong. In that case, they email body will be identical, the headers slightly different.&lt;br /&gt;
&lt;br /&gt;
In a different case, the user may &#039;reply&#039; to the message twice. Perhaps in error, perhaps purposefully. What to do depends on the specific scenario.&lt;br /&gt;
&lt;br /&gt;
We /could/ support better protection at the framework level, by keeping track of every reply-to address we send out. We decided against that because (a) the performance impact will be important (b) we want the 1st cut to be lightweight and simple to change in case we need to.&lt;br /&gt;
&lt;br /&gt;
With this the initial implementation, modules should expose functions that handle these &amp;quot;replay&amp;quot; cases correctly. If later we want to expose additional functions, we can add such tracking as an optional thing. It&#039;d be awful to have it across all emails sent from Moodle.&lt;br /&gt;
&lt;br /&gt;
== Experimental email processing, pending merge into 1.9/2.0 ==&lt;br /&gt;
===Module Authors===&lt;br /&gt;
The email interface allows you to let users respond to emails sent via your module and affect change in them. The basic idea is that each email is uniquely identified with an email session that carries with it a simple payload. This payload is stored via database, and cannot be changed by the user. Replies are handled by module code in your lib.php library - modulename_process_email($payload, $body) - which is passed the session payload and the body (with full headers) of the email received, to be parsed as you like. Some utility functions are available as well to help with this.&lt;br /&gt;
&lt;br /&gt;
Here is an outline of the intended use:&lt;br /&gt;
* Before sending an email to a user via the email_to_user() function, the module should check to see if the config variable $CFG-&amp;gt;emailinterface is enabled. (This is off by default)&lt;br /&gt;
* Assuming the email interface is enabled, the function generate_email_verp_address($moduleid, $payload, $userid) should be called to create an &amp;quot;email session&amp;quot;. The payload should include any data you wish to use in your handling routine - such as the id of the user, or what part of the interface he is interacting with. The function will return a string containing the email session id.&lt;br /&gt;
* Call the email_to_user() function as normal, appending the email session id as the 11th parameter. Keep in mind that you will probably also need to change the text or html of the email to point out that the email interface is active.&lt;br /&gt;
* A function contained in the lib.php file of your module, named [modulename]_process_email($payload, $body) should be written. This is the handler function, which is called when an email reply is received. This function can inspect the contents of the payload received, then parse the email body for data. The $body parameter returns the full email, including the headers.&lt;br /&gt;
&lt;br /&gt;
Note that each email can only be replied to once - the email session is destroyed once an email has been received. If you wish to have multiple replies from a user, you will have to create a new session (and new email) every time. The email session table is also regularly pruned, the default settings allow sessions to persist for one month.&lt;br /&gt;
&lt;br /&gt;
The following utility functions are also defined in admin/process_email.php, which can help:&lt;br /&gt;
* get_email_subject($fullemail) - return the subject of an email&lt;br /&gt;
* strip_email_headers($fullemail) - strip all headers off an email&lt;br /&gt;
* email_is_multipart($fullemail) - determine if an email is a multipart message&lt;br /&gt;
* seperate_multipart($multipartmsg) - seperate a multipart email message into an array of parts, each of which has headers and a body.&lt;br /&gt;
* get_multipart_content_type($part) - determine the content-type of a multipart, generally text/plain or text/html.&lt;br /&gt;
* multipart_is_quoted_printable($part) - determine if a email part has been encoded with the quoted-printable encoding - some email clients tend to do this to html.&lt;br /&gt;
* decode_quoted_printable($partdata) - decode a email that has been encoded with quoted-printable encoding - this needs to be run on the data section of a part (strip_email_headers can be used to seperate the headers of a part).&lt;br /&gt;
* strip_email_reply($body, $ishtml, $identifier) - strip all irrelevant lines of an email message based on a unique identifier embedded within the original message. This is used to determine what is user input, and what is irrelevant data the email client has added.&lt;br /&gt;
* strip_email_reply_multi($body, $ishtml, $identifier) - as above, but allowing for multiple sections of possible user input in a single email message.&lt;br /&gt;
&lt;br /&gt;
Examples of use of these functions can be seen in the handler for the forum module. The idea behind the strip reply functions is that the original email will contain a unique identifier, such as a random 10 character string. This is embedded in a line with instructions for the user to write below and above it, e.g:&lt;br /&gt;
  \/ Please put your response here [ABCDEFGHIJ] \/&lt;br /&gt;
  &amp;lt;User Data&amp;gt;&lt;br /&gt;
  /\ Please put your response here [ABCDEFGHIJ] /\&lt;br /&gt;
This is necessary because of the wide differences between webmail and email clients in handling quotes and prefixing dates/times to replied emails. Keep in mind that text emails have an 80-character line width restrictions, which must also include the quote added by the email client, so any line of a text-email with this identifier should be kept to at least 77 characters to avoid wrapping by an email client. This unique identifier can be easily stored in the payload. Multiple input sections are handled similarly - a number is appended to the end of the identifier, e.g. [ABCDEFGHIJ1] to signfiy the first section of input. The strip_email_reply_multi returns an array containing a map from each numbered section it finds to a string containing all data in that section.&lt;br /&gt;
&lt;br /&gt;
===Developer Info===&lt;br /&gt;
The reply-to header is now encoded in base32 instead of base64 to allow for case-insensitive MTA&#039;s. Generate_email_processing_address was left as a backwards-compatibility wrapper, modules should use generate_email_verp_address now instead.&lt;br /&gt;
&lt;br /&gt;
Email sessions have been created to deal with the lack of space avaliable in the header under base32, payloads are stored in a new table mdl_email_sessions, and are identified with a unique base32 key which is embedded in the reply-to header. Each row has a timestamp, and the table is pruned during cleanup cron in admin/cron.php.&lt;br /&gt;
&lt;br /&gt;
Bounce detection is now linked in with the email interface - bounce detection is included in admin/process_email.php. Some new configuration variables have also been created to help configure these changes - $CFG-&amp;gt;emailinterface and $CFG-&amp;gt;emailsessiontime - and both have been added to the server settings admin page.&lt;br /&gt;
&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27327</id>
		<title>Email processing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27327"/>
		<updated>2007-09-26T18:44:07Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* Email confirmation or registration words */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Features ==&lt;br /&gt;
&lt;br /&gt;
Moodle now makes better use of the SMTP protocol and email in general. Most of the benefits result from using a technique known as Variable Envelope Return Path (VERP).&lt;br /&gt;
&lt;br /&gt;
* Works on most modern MTAs (at least on Unix systems).&lt;br /&gt;
* All processing of bounces and replies is secured using HMAC-MD5-8.&lt;br /&gt;
* Bounces are handled correctly and increase a &amp;quot;bad email&amp;quot; score for the user.&lt;br /&gt;
* noreply@host address is now on Reply-to field, avoiding accidental pollution of users address books.&lt;br /&gt;
* noreply@host has an autorresponder&lt;br /&gt;
* Makes it easy for modules to send emails with a signed VERP reply-to.&lt;br /&gt;
* Handles receving of VERP replies: Validates the HMAC-MD5-8 signature and Dispatches the encoded request data to the relevant module&lt;br /&gt;
&lt;br /&gt;
== Moodle configuration ==&lt;br /&gt;
&lt;br /&gt;
Edit config.php to enable bounce handling, and setup Moodle to match your MTA configuration. Here&#039;s how. Uncomment these lines in config.php (if you cannot find them, copy them from config-dist.php):&lt;br /&gt;
&lt;br /&gt;
  // once handlebounces is true, we will be using VERP for the return address of every sent email&lt;br /&gt;
  $CFG-&amp;gt;handlebounces = true;&lt;br /&gt;
  // minimum bounces allowed per user&lt;br /&gt;
  $CFG-&amp;gt;minbounces = 10;&lt;br /&gt;
  // ratio of bad emails to sent emails&lt;br /&gt;
  // if we get more than 20% bounces &lt;br /&gt;
  // for a given user, his/her email is marked bad&lt;br /&gt;
  $CFG-&amp;gt;bounceratio = .20;&lt;br /&gt;
&lt;br /&gt;
Edit the $CFG-&amp;gt;maildomain line and one of the $CFG-&amp;gt;mailprefix lines (the one that matches your MTA).&lt;br /&gt;
&lt;br /&gt;
Make sure your server has a command-line PHP interpreter, and that it is able to connect to mysql (or postgres if relevant). If you are able to run cron.php from the commandline or from crontab, this means PHP is ok.&lt;br /&gt;
&lt;br /&gt;
Edit the process_email.php script to point to the location of your php binary. It will usually be &#039;&#039;/usr/bin/php&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Email confirmation or registration words==&lt;br /&gt;
*  Students receive a confirmation email when they create a user account.  This text can be found in the lang/?/moodle.php as the emailconfirmation &amp;quot;variable&amp;quot;.&lt;br /&gt;
* Students receive a welcome email when they enroll in a course.  This text can be found in the lang/?/moodle.php file as the welcometocoursetext &amp;quot;variable&amp;quot;.&lt;br /&gt;
*If you feel the need to edit this text, the best way to do this is to go to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit. Once you have done this, hit the &amp;quot;Switch lang directory&amp;quot; button, and do your editing.&lt;br /&gt;
*If you decide to get your hands dirty and work by editing the moodle.php directly, be careful to open the file only in a simple text editor like notepad or wordpad. &lt;br /&gt;
*Tip: Be careful with markup - as you edit, you must use &amp;quot; &amp;quot; for things like putting in hyperlinks, titles and targets. You MUST &#039;escape&#039; them by putting a \ before each &amp;quot;. If you don&#039;t the resulting page will appear blank.&lt;br /&gt;
**Use &amp;lt;nowiki&amp;gt;&amp;lt;a href=\&amp;quot;http://www.blah_blah\&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** Do not use &amp;lt;nowiki&amp;gt;&amp;lt;a href=&amp;quot;http://www.blah_blah&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt; &lt;br /&gt;
**Use the \ before target= and title= and other similar codes, anywhere you must use &amp;quot; in the markup.&lt;br /&gt;
*If you feel you must really go the route of editing the moodle.php file directly, save a copy of the file in its own folder (copy and paste the file in the same folder). That way, if it all goes wrong for you, all you have to do is delete the botched file and rename the &#039;copy of moodle.php&#039; back to &#039;moodle.php&#039; and you are back to square one, no harm done!&lt;br /&gt;
*Having said all that, it is best to do all your editing in the web interface by going to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit.&lt;br /&gt;
&lt;br /&gt;
Make sure &#039;&#039;process_email.php&#039;&#039; is executable by running &amp;quot;chmod ugo+rx process_email.php&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Setup under Postfix ==&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;|&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; and moodle installed under /var/www/moodle we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
== Setup under Qmail ==&lt;br /&gt;
&lt;br /&gt;
Depending on your setup, your aliases will be controlled by one or more of&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;/etc/aliases&#039;&#039;&lt;br /&gt;
* &#039;&#039;/var/qmail/alias/.qmail-PREFIX&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you edit /etc/aliases add a line like this (for a prefix of &#039;mdl&#039;):&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you create /var/qmail/alias/.qmail-PREFIX, just do&lt;br /&gt;
&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-mdl&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-noreply&lt;br /&gt;
&lt;br /&gt;
To this three letter prefix, we will add a &#039;-&#039; when sending and receiving messages. For more info, check out the manpage for dot-qmail.&lt;br /&gt;
&lt;br /&gt;
== Setup under Exim ==&lt;br /&gt;
&lt;br /&gt;
Open &#039;&#039;/etc/exim/exim.conf&#039;&#039; and add to trusted_users the user Apache and cron.php run as (usually &amp;quot;www-data&amp;quot; or &amp;quot;nobody&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;+&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
More documentation about Exim can be found [http://www.exim.org/docs.html here]. You may have to tell Exim not to lowercase the local-part.&lt;br /&gt;
&lt;br /&gt;
== Developer info ==&lt;br /&gt;
&lt;br /&gt;
Changed functions:&lt;br /&gt;
&lt;br /&gt;
* email_to_user() will set the envelope sender to a special bounce processing address (based on $CFG settings)&lt;br /&gt;
* email_to_user() will accept (and set) a reply-to header, to be generated by the module calling the function.&lt;br /&gt;
* associated string changes/additions&lt;br /&gt;
&lt;br /&gt;
New functions:&lt;br /&gt;
&lt;br /&gt;
* generate_email_processing_address() - ALWAYS use this to generate the reply-to header. reply-to header will look like this: (LIMIT: 64 chars total) prefix - EXACTLY four chars encodeded, packed, moduleid (0 for core) (2 chars) up to 42 chars for the modules to put anything they want it (can contain userid (or, eg for forum, postids to reply to), or anything really. 42 chars is ABSOLUTE LIMIT) 16 char hash (half an md5) of the first part of the address, together with a site &amp;quot;secret&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* moodle_process_email() - any non-module email processing goes here (currently used for processing bounces)&lt;br /&gt;
&lt;br /&gt;
New files:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/process_email.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This script needs to be called from your MTA for anything starting with the 3 char prefix described above (and optionally, the noreply address).&lt;br /&gt;
&lt;br /&gt;
How does it work? It will break down and unencode the email address into moduleid and validate the half md5 hash, and call $modname_process_email (if it exists). Arguments to these functions are: $modargs (any part of the email address that isn&#039;t the prefix, modid or the hash) and the contents of the email (read from STDIN).&lt;br /&gt;
&lt;br /&gt;
It doubles up as the noreplyaddress autorresponder if you configure it with that address as well. Replying with a friendly &amp;quot;this is not a real email address&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
== Module Authors ==&lt;br /&gt;
&lt;br /&gt;
Take a look at new functions moodle_process_email() and generate_email_processing_address() in moodlelib.php for ideas about how to&lt;br /&gt;
&lt;br /&gt;
* encode and unencode the arguments your module needs to do the processing&lt;br /&gt;
* how to deal with multiple &amp;quot;actions&amp;quot; for any given module.&lt;br /&gt;
&lt;br /&gt;
In a nutshell, users can send emails to Moodle using special dynamic addresses. These emails can trigger a call to a module function in the form of modulename_process_email($str, $bodyofemail). The $str part will be up to 42 characters of data generated by Moodle (presumably by your own module), and the $bodyofemailpart is the contents of the email (got by reading STDIN - usually generated by the users MUA).&lt;br /&gt;
&lt;br /&gt;
The 42 characters come from the &amp;quot;local part&amp;quot; of an email address (the part before the @ sign) which can have up to 64 chars. Out of those 64 chars, Moodle uses 22 characters, leaving you with 42 characters to encode data.&lt;br /&gt;
&lt;br /&gt;
What do we do with the 22 chars? Four go to the prefix, which we need to let the MTA know to pass the message to our script. Two go to identify the module ID so we know which module has generated the message (and so we dispatch the request to that module). The remaining 16 are a signature (HMAC-MD5-8) we use to authenticate the message.&lt;br /&gt;
&lt;br /&gt;
Forty-two characters isn&#039;t a lot (although it could be the answer to life, the universe, and everything!) so make sure you use those characters wisely.&lt;br /&gt;
&lt;br /&gt;
The most efficient way to encode database IDs in their full range (so that they can be placed in an email address) we have found is base64_encode(pack(&#039;V&#039;,2147483647)), which returns &amp;quot;/ / / / f w = =&amp;quot;. The two trailing &amp;quot;= =&amp;quot; are redundant and you can remove them (you&#039;ll need to reappend them when retrieving your data). Join your parameters as encoded IDs in positional slots for efficiency.&lt;br /&gt;
&lt;br /&gt;
To retrieve your data, use substr() to separate your parameters, and then unpack(&#039;V&#039;,base64_decode($str)). Note that it&#039;ll return a one-element array.&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Using &#039;V&#039; reaches 2147483647, half the range of mySQL&#039;s INT. Additionally, &#039;V&#039; behaves like a signed value, rather than an unsigned, so I suspect there&#039;s a bug in PHP&#039;s documentation of pack().&lt;br /&gt;
&lt;br /&gt;
With each ID taking 6-chars (8 chars if we find a way to use the full range of &#039;V&#039;), you have a limited number of parameters. If you need to encode more information, store it in the DB and send emails that point to your stored data. Remember to cleanup this temporary data after a safe period of time.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Do not try to use variable-width encoding to put IDs, as it&#039;ll work in small installations and break in larger ones.&lt;br /&gt;
&lt;br /&gt;
== Security issues ==&lt;br /&gt;
&lt;br /&gt;
Any code in modulename_process_email() _must_ assume it will see repeat replies and handle them gracefully. The definition of &#039;gracefully&#039; depends on what the code does.&lt;br /&gt;
&lt;br /&gt;
Email servers (MTAs) will sometimes re-transmit a message if they are unsure that the receiving MTA got it -- and sysadmins may sometimes replay a whole email queue if something&#039;s gone wrong. In that case, they email body will be identical, the headers slightly different.&lt;br /&gt;
&lt;br /&gt;
In a different case, the user may &#039;reply&#039; to the message twice. Perhaps in error, perhaps purposefully. What to do depends on the specific scenario.&lt;br /&gt;
&lt;br /&gt;
We /could/ support better protection at the framework level, by keeping track of every reply-to address we send out. We decided against that because (a) the performance impact will be important (b) we want the 1st cut to be lightweight and simple to change in case we need to.&lt;br /&gt;
&lt;br /&gt;
With this the initial implementation, modules should expose functions that handle these &amp;quot;replay&amp;quot; cases correctly. If later we want to expose additional functions, we can add such tracking as an optional thing. It&#039;d be awful to have it across all emails sent from Moodle.&lt;br /&gt;
&lt;br /&gt;
== Experimental email processing, pending merge into 1.9/2.0 ==&lt;br /&gt;
===Module Authors===&lt;br /&gt;
The email interface allows you to let users respond to emails sent via your module and affect change in them. The basic idea is that each email is uniquely identified with an email session that carries with it a simple payload. This payload is stored via database, and cannot be changed by the user. Replies are handled by module code in your lib.php library - modulename_process_email($payload, $body) - which is passed the session payload and the body (with full headers) of the email received, to be parsed as you like. Some utility functions are available as well to help with this.&lt;br /&gt;
&lt;br /&gt;
Here is an outline of the intended use:&lt;br /&gt;
* Before sending an email to a user via the email_to_user() function, the module should check to see if the config variable $CFG-&amp;gt;emailinterface is enabled. (This is off by default)&lt;br /&gt;
* Assuming the email interface is enabled, the function generate_email_verp_address($moduleid, $payload, $userid) should be called to create an &amp;quot;email session&amp;quot;. The payload should include any data you wish to use in your handling routine - such as the id of the user, or what part of the interface he is interacting with. The function will return a string containing the email session id.&lt;br /&gt;
* Call the email_to_user() function as normal, appending the email session id as the 11th parameter. Keep in mind that you will probably also need to change the text or html of the email to point out that the email interface is active.&lt;br /&gt;
* A function contained in the lib.php file of your module, named [modulename]_process_email($payload, $body) should be written. This is the handler function, which is called when an email reply is received. This function can inspect the contents of the payload received, then parse the email body for data. The $body parameter returns the full email, including the headers.&lt;br /&gt;
&lt;br /&gt;
Note that each email can only be replied to once - the email session is destroyed once an email has been received. If you wish to have multiple replies from a user, you will have to create a new session (and new email) every time. The email session table is also regularly pruned, the default settings allow sessions to persist for one month.&lt;br /&gt;
&lt;br /&gt;
The following utility functions are also defined in admin/process_email.php, which can help:&lt;br /&gt;
* get_email_subject($fullemail) - return the subject of an email&lt;br /&gt;
* strip_email_headers($fullemail) - strip all headers off an email&lt;br /&gt;
* email_is_multipart($fullemail) - determine if an email is a multipart message&lt;br /&gt;
* seperate_multipart($multipartmsg) - seperate a multipart email message into an array of parts, each of which has headers and a body.&lt;br /&gt;
* get_multipart_content_type($part) - determine the content-type of a multipart, generally text/plain or text/html.&lt;br /&gt;
* multipart_is_quoted_printable($part) - determine if a email part has been encoded with the quoted-printable encoding - some email clients tend to do this to html.&lt;br /&gt;
* decode_quoted_printable($partdata) - decode a email that has been encoded with quoted-printable encoding - this needs to be run on the data section of a part (strip_email_headers can be used to seperate the headers of a part).&lt;br /&gt;
* strip_email_reply($body, $ishtml, $identifier) - strip all irrelevant lines of an email message based on a unique identifier embedded within the original message. This is used to determine what is user input, and what is irrelevant data the email client has added.&lt;br /&gt;
* strip_email_reply_multi($body, $ishtml, $identifier) - as above, but allowing for multiple sections of possible user input in a single email message.&lt;br /&gt;
&lt;br /&gt;
Examples of use of these functions can be seen in the handler for the forum module. The idea behind the strip reply functions is that the original email will contain a unique identifier, such as a random 10 character string. This is embedded in a line with instructions for the user to write below and above it, e.g:&lt;br /&gt;
  \/ Please put your response here [ABCDEFGHIJ] \/&lt;br /&gt;
  &amp;lt;User Data&amp;gt;&lt;br /&gt;
  /\ Please put your response here [ABCDEFGHIJ] /\&lt;br /&gt;
This is necessary because of the wide differences between webmail and email clients in handling quotes and prefixing dates/times to replied emails. Keep in mind that text emails have an 80-character line width restrictions, which must also include the quote added by the email client, so any line of a text-email with this identifier should be kept to at least 77 characters to avoid wrapping by an email client. This unique identifier can be easily stored in the payload. Multiple input sections are handled similarly - a number is appended to the end of the identifier, e.g. [ABCDEFGHIJ1] to signfiy the first section of input. The strip_email_reply_multi returns an array containing a map from each numbered section it finds to a string containing all data in that section.&lt;br /&gt;
&lt;br /&gt;
===Developer Info===&lt;br /&gt;
The reply-to header is now encoded in base32 instead of base64 to allow for case-insensitive MTA&#039;s. Generate_email_processing_address was left as a backwards-compatibility wrapper, modules should use generate_email_verp_address now instead.&lt;br /&gt;
&lt;br /&gt;
Email sessions have been created to deal with the lack of space avaliable in the header under base32, payloads are stored in a new table mdl_email_sessions, and are identified with a unique base32 key which is embedded in the reply-to header. Each row has a timestamp, and the table is pruned during cleanup cron in admin/cron.php.&lt;br /&gt;
&lt;br /&gt;
Bounce detection is now linked in with the email interface - bounce detection is included in admin/process_email.php. Some new configuration variables have also been created to help configure these changes - $CFG-&amp;gt;emailinterface and $CFG-&amp;gt;emailsessiontime - and both have been added to the server settings admin page.&lt;br /&gt;
&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27326</id>
		<title>Email processing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27326"/>
		<updated>2007-09-26T18:43:20Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* Email confirmation or registration words */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Features ==&lt;br /&gt;
&lt;br /&gt;
Moodle now makes better use of the SMTP protocol and email in general. Most of the benefits result from using a technique known as Variable Envelope Return Path (VERP).&lt;br /&gt;
&lt;br /&gt;
* Works on most modern MTAs (at least on Unix systems).&lt;br /&gt;
* All processing of bounces and replies is secured using HMAC-MD5-8.&lt;br /&gt;
* Bounces are handled correctly and increase a &amp;quot;bad email&amp;quot; score for the user.&lt;br /&gt;
* noreply@host address is now on Reply-to field, avoiding accidental pollution of users address books.&lt;br /&gt;
* noreply@host has an autorresponder&lt;br /&gt;
* Makes it easy for modules to send emails with a signed VERP reply-to.&lt;br /&gt;
* Handles receving of VERP replies: Validates the HMAC-MD5-8 signature and Dispatches the encoded request data to the relevant module&lt;br /&gt;
&lt;br /&gt;
== Moodle configuration ==&lt;br /&gt;
&lt;br /&gt;
Edit config.php to enable bounce handling, and setup Moodle to match your MTA configuration. Here&#039;s how. Uncomment these lines in config.php (if you cannot find them, copy them from config-dist.php):&lt;br /&gt;
&lt;br /&gt;
  // once handlebounces is true, we will be using VERP for the return address of every sent email&lt;br /&gt;
  $CFG-&amp;gt;handlebounces = true;&lt;br /&gt;
  // minimum bounces allowed per user&lt;br /&gt;
  $CFG-&amp;gt;minbounces = 10;&lt;br /&gt;
  // ratio of bad emails to sent emails&lt;br /&gt;
  // if we get more than 20% bounces &lt;br /&gt;
  // for a given user, his/her email is marked bad&lt;br /&gt;
  $CFG-&amp;gt;bounceratio = .20;&lt;br /&gt;
&lt;br /&gt;
Edit the $CFG-&amp;gt;maildomain line and one of the $CFG-&amp;gt;mailprefix lines (the one that matches your MTA).&lt;br /&gt;
&lt;br /&gt;
Make sure your server has a command-line PHP interpreter, and that it is able to connect to mysql (or postgres if relevant). If you are able to run cron.php from the commandline or from crontab, this means PHP is ok.&lt;br /&gt;
&lt;br /&gt;
Edit the process_email.php script to point to the location of your php binary. It will usually be &#039;&#039;/usr/bin/php&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Email confirmation or registration words==&lt;br /&gt;
*  Students receive a confirmation email when they create a user account.  This text can be found in the lang/?/moodle.php as the emailconfirmation &amp;quot;variable&amp;quot;.&lt;br /&gt;
* Students receive a welcome email when they enroll in a course.  This text can be found in the lang/?/moodle.php file as the welcometocoursetext &amp;quot;variable&amp;quot;.&lt;br /&gt;
*If you feel the need to edit this text, the best way to do this is to go to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit. Once you have done this, hit the &amp;quot;Switch lang directory&amp;quot; button, and do your editing.&lt;br /&gt;
*If you decide to get your hands dirty and work by editing the moodle.php directly, be careful to open the file only in a simple text editor like notepad or wordpad. &lt;br /&gt;
*Tip: Be careful with markup - as you edit, you must use &amp;quot; for things like putting in hyperlinks, titles and targets. You MUST &#039;escape&#039; them by putting a \ before each &amp;quot;. If you don&#039;t the resulting page will appear blank.&lt;br /&gt;
**Use &amp;lt;nowiki&amp;gt;&amp;lt;a href=\&amp;quot;http://www.blah_blah\&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
** Do not use &amp;lt;nowiki&amp;gt;&amp;lt;a href=&amp;quot;http://www.blah_blah&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt; &lt;br /&gt;
**Use the \ before target= and title= and other similar codes, anywhere you must use &amp;quot; in the markup.&lt;br /&gt;
*If you feel you must really go the route of editing the moodle.php file directly, save a copy of the file in its own folder (copy and paste the file in the same folder). That way, if it all goes wrong for you, all you have to do is delete the botched file and rename the &#039;copy of moodle.php&#039; back to &#039;moodle.php&#039; and you are back to square one, no harm done!&lt;br /&gt;
*Having said all that, it is best to do all your editing in the web interface by going to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit.&lt;br /&gt;
&lt;br /&gt;
Make sure &#039;&#039;process_email.php&#039;&#039; is executable by running &amp;quot;chmod ugo+rx process_email.php&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Setup under Postfix ==&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;|&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; and moodle installed under /var/www/moodle we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
== Setup under Qmail ==&lt;br /&gt;
&lt;br /&gt;
Depending on your setup, your aliases will be controlled by one or more of&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;/etc/aliases&#039;&#039;&lt;br /&gt;
* &#039;&#039;/var/qmail/alias/.qmail-PREFIX&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you edit /etc/aliases add a line like this (for a prefix of &#039;mdl&#039;):&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you create /var/qmail/alias/.qmail-PREFIX, just do&lt;br /&gt;
&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-mdl&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-noreply&lt;br /&gt;
&lt;br /&gt;
To this three letter prefix, we will add a &#039;-&#039; when sending and receiving messages. For more info, check out the manpage for dot-qmail.&lt;br /&gt;
&lt;br /&gt;
== Setup under Exim ==&lt;br /&gt;
&lt;br /&gt;
Open &#039;&#039;/etc/exim/exim.conf&#039;&#039; and add to trusted_users the user Apache and cron.php run as (usually &amp;quot;www-data&amp;quot; or &amp;quot;nobody&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;+&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
More documentation about Exim can be found [http://www.exim.org/docs.html here]. You may have to tell Exim not to lowercase the local-part.&lt;br /&gt;
&lt;br /&gt;
== Developer info ==&lt;br /&gt;
&lt;br /&gt;
Changed functions:&lt;br /&gt;
&lt;br /&gt;
* email_to_user() will set the envelope sender to a special bounce processing address (based on $CFG settings)&lt;br /&gt;
* email_to_user() will accept (and set) a reply-to header, to be generated by the module calling the function.&lt;br /&gt;
* associated string changes/additions&lt;br /&gt;
&lt;br /&gt;
New functions:&lt;br /&gt;
&lt;br /&gt;
* generate_email_processing_address() - ALWAYS use this to generate the reply-to header. reply-to header will look like this: (LIMIT: 64 chars total) prefix - EXACTLY four chars encodeded, packed, moduleid (0 for core) (2 chars) up to 42 chars for the modules to put anything they want it (can contain userid (or, eg for forum, postids to reply to), or anything really. 42 chars is ABSOLUTE LIMIT) 16 char hash (half an md5) of the first part of the address, together with a site &amp;quot;secret&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* moodle_process_email() - any non-module email processing goes here (currently used for processing bounces)&lt;br /&gt;
&lt;br /&gt;
New files:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/process_email.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This script needs to be called from your MTA for anything starting with the 3 char prefix described above (and optionally, the noreply address).&lt;br /&gt;
&lt;br /&gt;
How does it work? It will break down and unencode the email address into moduleid and validate the half md5 hash, and call $modname_process_email (if it exists). Arguments to these functions are: $modargs (any part of the email address that isn&#039;t the prefix, modid or the hash) and the contents of the email (read from STDIN).&lt;br /&gt;
&lt;br /&gt;
It doubles up as the noreplyaddress autorresponder if you configure it with that address as well. Replying with a friendly &amp;quot;this is not a real email address&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
== Module Authors ==&lt;br /&gt;
&lt;br /&gt;
Take a look at new functions moodle_process_email() and generate_email_processing_address() in moodlelib.php for ideas about how to&lt;br /&gt;
&lt;br /&gt;
* encode and unencode the arguments your module needs to do the processing&lt;br /&gt;
* how to deal with multiple &amp;quot;actions&amp;quot; for any given module.&lt;br /&gt;
&lt;br /&gt;
In a nutshell, users can send emails to Moodle using special dynamic addresses. These emails can trigger a call to a module function in the form of modulename_process_email($str, $bodyofemail). The $str part will be up to 42 characters of data generated by Moodle (presumably by your own module), and the $bodyofemailpart is the contents of the email (got by reading STDIN - usually generated by the users MUA).&lt;br /&gt;
&lt;br /&gt;
The 42 characters come from the &amp;quot;local part&amp;quot; of an email address (the part before the @ sign) which can have up to 64 chars. Out of those 64 chars, Moodle uses 22 characters, leaving you with 42 characters to encode data.&lt;br /&gt;
&lt;br /&gt;
What do we do with the 22 chars? Four go to the prefix, which we need to let the MTA know to pass the message to our script. Two go to identify the module ID so we know which module has generated the message (and so we dispatch the request to that module). The remaining 16 are a signature (HMAC-MD5-8) we use to authenticate the message.&lt;br /&gt;
&lt;br /&gt;
Forty-two characters isn&#039;t a lot (although it could be the answer to life, the universe, and everything!) so make sure you use those characters wisely.&lt;br /&gt;
&lt;br /&gt;
The most efficient way to encode database IDs in their full range (so that they can be placed in an email address) we have found is base64_encode(pack(&#039;V&#039;,2147483647)), which returns &amp;quot;/ / / / f w = =&amp;quot;. The two trailing &amp;quot;= =&amp;quot; are redundant and you can remove them (you&#039;ll need to reappend them when retrieving your data). Join your parameters as encoded IDs in positional slots for efficiency.&lt;br /&gt;
&lt;br /&gt;
To retrieve your data, use substr() to separate your parameters, and then unpack(&#039;V&#039;,base64_decode($str)). Note that it&#039;ll return a one-element array.&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Using &#039;V&#039; reaches 2147483647, half the range of mySQL&#039;s INT. Additionally, &#039;V&#039; behaves like a signed value, rather than an unsigned, so I suspect there&#039;s a bug in PHP&#039;s documentation of pack().&lt;br /&gt;
&lt;br /&gt;
With each ID taking 6-chars (8 chars if we find a way to use the full range of &#039;V&#039;), you have a limited number of parameters. If you need to encode more information, store it in the DB and send emails that point to your stored data. Remember to cleanup this temporary data after a safe period of time.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Do not try to use variable-width encoding to put IDs, as it&#039;ll work in small installations and break in larger ones.&lt;br /&gt;
&lt;br /&gt;
== Security issues ==&lt;br /&gt;
&lt;br /&gt;
Any code in modulename_process_email() _must_ assume it will see repeat replies and handle them gracefully. The definition of &#039;gracefully&#039; depends on what the code does.&lt;br /&gt;
&lt;br /&gt;
Email servers (MTAs) will sometimes re-transmit a message if they are unsure that the receiving MTA got it -- and sysadmins may sometimes replay a whole email queue if something&#039;s gone wrong. In that case, they email body will be identical, the headers slightly different.&lt;br /&gt;
&lt;br /&gt;
In a different case, the user may &#039;reply&#039; to the message twice. Perhaps in error, perhaps purposefully. What to do depends on the specific scenario.&lt;br /&gt;
&lt;br /&gt;
We /could/ support better protection at the framework level, by keeping track of every reply-to address we send out. We decided against that because (a) the performance impact will be important (b) we want the 1st cut to be lightweight and simple to change in case we need to.&lt;br /&gt;
&lt;br /&gt;
With this the initial implementation, modules should expose functions that handle these &amp;quot;replay&amp;quot; cases correctly. If later we want to expose additional functions, we can add such tracking as an optional thing. It&#039;d be awful to have it across all emails sent from Moodle.&lt;br /&gt;
&lt;br /&gt;
== Experimental email processing, pending merge into 1.9/2.0 ==&lt;br /&gt;
===Module Authors===&lt;br /&gt;
The email interface allows you to let users respond to emails sent via your module and affect change in them. The basic idea is that each email is uniquely identified with an email session that carries with it a simple payload. This payload is stored via database, and cannot be changed by the user. Replies are handled by module code in your lib.php library - modulename_process_email($payload, $body) - which is passed the session payload and the body (with full headers) of the email received, to be parsed as you like. Some utility functions are available as well to help with this.&lt;br /&gt;
&lt;br /&gt;
Here is an outline of the intended use:&lt;br /&gt;
* Before sending an email to a user via the email_to_user() function, the module should check to see if the config variable $CFG-&amp;gt;emailinterface is enabled. (This is off by default)&lt;br /&gt;
* Assuming the email interface is enabled, the function generate_email_verp_address($moduleid, $payload, $userid) should be called to create an &amp;quot;email session&amp;quot;. The payload should include any data you wish to use in your handling routine - such as the id of the user, or what part of the interface he is interacting with. The function will return a string containing the email session id.&lt;br /&gt;
* Call the email_to_user() function as normal, appending the email session id as the 11th parameter. Keep in mind that you will probably also need to change the text or html of the email to point out that the email interface is active.&lt;br /&gt;
* A function contained in the lib.php file of your module, named [modulename]_process_email($payload, $body) should be written. This is the handler function, which is called when an email reply is received. This function can inspect the contents of the payload received, then parse the email body for data. The $body parameter returns the full email, including the headers.&lt;br /&gt;
&lt;br /&gt;
Note that each email can only be replied to once - the email session is destroyed once an email has been received. If you wish to have multiple replies from a user, you will have to create a new session (and new email) every time. The email session table is also regularly pruned, the default settings allow sessions to persist for one month.&lt;br /&gt;
&lt;br /&gt;
The following utility functions are also defined in admin/process_email.php, which can help:&lt;br /&gt;
* get_email_subject($fullemail) - return the subject of an email&lt;br /&gt;
* strip_email_headers($fullemail) - strip all headers off an email&lt;br /&gt;
* email_is_multipart($fullemail) - determine if an email is a multipart message&lt;br /&gt;
* seperate_multipart($multipartmsg) - seperate a multipart email message into an array of parts, each of which has headers and a body.&lt;br /&gt;
* get_multipart_content_type($part) - determine the content-type of a multipart, generally text/plain or text/html.&lt;br /&gt;
* multipart_is_quoted_printable($part) - determine if a email part has been encoded with the quoted-printable encoding - some email clients tend to do this to html.&lt;br /&gt;
* decode_quoted_printable($partdata) - decode a email that has been encoded with quoted-printable encoding - this needs to be run on the data section of a part (strip_email_headers can be used to seperate the headers of a part).&lt;br /&gt;
* strip_email_reply($body, $ishtml, $identifier) - strip all irrelevant lines of an email message based on a unique identifier embedded within the original message. This is used to determine what is user input, and what is irrelevant data the email client has added.&lt;br /&gt;
* strip_email_reply_multi($body, $ishtml, $identifier) - as above, but allowing for multiple sections of possible user input in a single email message.&lt;br /&gt;
&lt;br /&gt;
Examples of use of these functions can be seen in the handler for the forum module. The idea behind the strip reply functions is that the original email will contain a unique identifier, such as a random 10 character string. This is embedded in a line with instructions for the user to write below and above it, e.g:&lt;br /&gt;
  \/ Please put your response here [ABCDEFGHIJ] \/&lt;br /&gt;
  &amp;lt;User Data&amp;gt;&lt;br /&gt;
  /\ Please put your response here [ABCDEFGHIJ] /\&lt;br /&gt;
This is necessary because of the wide differences between webmail and email clients in handling quotes and prefixing dates/times to replied emails. Keep in mind that text emails have an 80-character line width restrictions, which must also include the quote added by the email client, so any line of a text-email with this identifier should be kept to at least 77 characters to avoid wrapping by an email client. This unique identifier can be easily stored in the payload. Multiple input sections are handled similarly - a number is appended to the end of the identifier, e.g. [ABCDEFGHIJ1] to signfiy the first section of input. The strip_email_reply_multi returns an array containing a map from each numbered section it finds to a string containing all data in that section.&lt;br /&gt;
&lt;br /&gt;
===Developer Info===&lt;br /&gt;
The reply-to header is now encoded in base32 instead of base64 to allow for case-insensitive MTA&#039;s. Generate_email_processing_address was left as a backwards-compatibility wrapper, modules should use generate_email_verp_address now instead.&lt;br /&gt;
&lt;br /&gt;
Email sessions have been created to deal with the lack of space avaliable in the header under base32, payloads are stored in a new table mdl_email_sessions, and are identified with a unique base32 key which is embedded in the reply-to header. Each row has a timestamp, and the table is pruned during cleanup cron in admin/cron.php.&lt;br /&gt;
&lt;br /&gt;
Bounce detection is now linked in with the email interface - bounce detection is included in admin/process_email.php. Some new configuration variables have also been created to help configure these changes - $CFG-&amp;gt;emailinterface and $CFG-&amp;gt;emailsessiontime - and both have been added to the server settings admin page.&lt;br /&gt;
&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27325</id>
		<title>Email processing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27325"/>
		<updated>2007-09-26T18:42:06Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* Email confirmation or registration words */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Features ==&lt;br /&gt;
&lt;br /&gt;
Moodle now makes better use of the SMTP protocol and email in general. Most of the benefits result from using a technique known as Variable Envelope Return Path (VERP).&lt;br /&gt;
&lt;br /&gt;
* Works on most modern MTAs (at least on Unix systems).&lt;br /&gt;
* All processing of bounces and replies is secured using HMAC-MD5-8.&lt;br /&gt;
* Bounces are handled correctly and increase a &amp;quot;bad email&amp;quot; score for the user.&lt;br /&gt;
* noreply@host address is now on Reply-to field, avoiding accidental pollution of users address books.&lt;br /&gt;
* noreply@host has an autorresponder&lt;br /&gt;
* Makes it easy for modules to send emails with a signed VERP reply-to.&lt;br /&gt;
* Handles receving of VERP replies: Validates the HMAC-MD5-8 signature and Dispatches the encoded request data to the relevant module&lt;br /&gt;
&lt;br /&gt;
== Moodle configuration ==&lt;br /&gt;
&lt;br /&gt;
Edit config.php to enable bounce handling, and setup Moodle to match your MTA configuration. Here&#039;s how. Uncomment these lines in config.php (if you cannot find them, copy them from config-dist.php):&lt;br /&gt;
&lt;br /&gt;
  // once handlebounces is true, we will be using VERP for the return address of every sent email&lt;br /&gt;
  $CFG-&amp;gt;handlebounces = true;&lt;br /&gt;
  // minimum bounces allowed per user&lt;br /&gt;
  $CFG-&amp;gt;minbounces = 10;&lt;br /&gt;
  // ratio of bad emails to sent emails&lt;br /&gt;
  // if we get more than 20% bounces &lt;br /&gt;
  // for a given user, his/her email is marked bad&lt;br /&gt;
  $CFG-&amp;gt;bounceratio = .20;&lt;br /&gt;
&lt;br /&gt;
Edit the $CFG-&amp;gt;maildomain line and one of the $CFG-&amp;gt;mailprefix lines (the one that matches your MTA).&lt;br /&gt;
&lt;br /&gt;
Make sure your server has a command-line PHP interpreter, and that it is able to connect to mysql (or postgres if relevant). If you are able to run cron.php from the commandline or from crontab, this means PHP is ok.&lt;br /&gt;
&lt;br /&gt;
Edit the process_email.php script to point to the location of your php binary. It will usually be &#039;&#039;/usr/bin/php&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Email confirmation or registration words==&lt;br /&gt;
*  Students receive a confirmation email when they create a user account.  This text can be found in the lang/?/moodle.php as the emailconfirmation &amp;quot;variable&amp;quot;.&lt;br /&gt;
* Students receive a welcome email when they enroll in a course.  This text can be found in the lang/?/moodle.php file as the welcometocoursetext &amp;quot;variable&amp;quot;.&lt;br /&gt;
*If you feel the need to edit this text, the best way to do this is to go to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit. Once you have done this, hit the &amp;quot;Switch lang directory&amp;quot; button, and do your editing.&lt;br /&gt;
*If you decide to get your hands dirty and work by editing the moodle.php directly, be careful to open the file only in a simple text editor like notepad or wordpad. &lt;br /&gt;
*Tip: Be careful with markup - as you edit, you must use &amp;quot; for things like putting in hyperlinks, titles and targets. You MUST &#039;escape&#039; them by putting a \ before each &amp;quot;. If you don&#039;t the resulting page will appear blank.&lt;br /&gt;
**Use &amp;lt;nowiki&amp;gt;&amp;lt;a href=\&amp;quot;http://www.blah_blah\&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
*** Do not use &amp;lt;nowiki&amp;gt;&amp;lt;a href=&amp;quot;http://www.blah_blah&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt; &lt;br /&gt;
**Use the \ before target= and title= and other similar codes, anywhere you must use &amp;quot; in the markup.&lt;br /&gt;
*If you feel you must really go the route of editing the moodle.php file directly, save a copy of the file in its own folder (copy and paste the file in the same folder). That way, if it all goes wrong for you, all you have to do is delete the botched file and rename the &#039;copy of moodle.php&#039; back to &#039;moodle.php&#039; and you are back to square one, no harm done!&lt;br /&gt;
*Having said all that, it is best to do all your editing in the web interface by going to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit.&lt;br /&gt;
&lt;br /&gt;
Make sure &#039;&#039;process_email.php&#039;&#039; is executable by running &amp;quot;chmod ugo+rx process_email.php&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Setup under Postfix ==&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;|&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; and moodle installed under /var/www/moodle we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
== Setup under Qmail ==&lt;br /&gt;
&lt;br /&gt;
Depending on your setup, your aliases will be controlled by one or more of&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;/etc/aliases&#039;&#039;&lt;br /&gt;
* &#039;&#039;/var/qmail/alias/.qmail-PREFIX&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you edit /etc/aliases add a line like this (for a prefix of &#039;mdl&#039;):&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you create /var/qmail/alias/.qmail-PREFIX, just do&lt;br /&gt;
&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-mdl&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-noreply&lt;br /&gt;
&lt;br /&gt;
To this three letter prefix, we will add a &#039;-&#039; when sending and receiving messages. For more info, check out the manpage for dot-qmail.&lt;br /&gt;
&lt;br /&gt;
== Setup under Exim ==&lt;br /&gt;
&lt;br /&gt;
Open &#039;&#039;/etc/exim/exim.conf&#039;&#039; and add to trusted_users the user Apache and cron.php run as (usually &amp;quot;www-data&amp;quot; or &amp;quot;nobody&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;+&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
More documentation about Exim can be found [http://www.exim.org/docs.html here]. You may have to tell Exim not to lowercase the local-part.&lt;br /&gt;
&lt;br /&gt;
== Developer info ==&lt;br /&gt;
&lt;br /&gt;
Changed functions:&lt;br /&gt;
&lt;br /&gt;
* email_to_user() will set the envelope sender to a special bounce processing address (based on $CFG settings)&lt;br /&gt;
* email_to_user() will accept (and set) a reply-to header, to be generated by the module calling the function.&lt;br /&gt;
* associated string changes/additions&lt;br /&gt;
&lt;br /&gt;
New functions:&lt;br /&gt;
&lt;br /&gt;
* generate_email_processing_address() - ALWAYS use this to generate the reply-to header. reply-to header will look like this: (LIMIT: 64 chars total) prefix - EXACTLY four chars encodeded, packed, moduleid (0 for core) (2 chars) up to 42 chars for the modules to put anything they want it (can contain userid (or, eg for forum, postids to reply to), or anything really. 42 chars is ABSOLUTE LIMIT) 16 char hash (half an md5) of the first part of the address, together with a site &amp;quot;secret&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* moodle_process_email() - any non-module email processing goes here (currently used for processing bounces)&lt;br /&gt;
&lt;br /&gt;
New files:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/process_email.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This script needs to be called from your MTA for anything starting with the 3 char prefix described above (and optionally, the noreply address).&lt;br /&gt;
&lt;br /&gt;
How does it work? It will break down and unencode the email address into moduleid and validate the half md5 hash, and call $modname_process_email (if it exists). Arguments to these functions are: $modargs (any part of the email address that isn&#039;t the prefix, modid or the hash) and the contents of the email (read from STDIN).&lt;br /&gt;
&lt;br /&gt;
It doubles up as the noreplyaddress autorresponder if you configure it with that address as well. Replying with a friendly &amp;quot;this is not a real email address&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
== Module Authors ==&lt;br /&gt;
&lt;br /&gt;
Take a look at new functions moodle_process_email() and generate_email_processing_address() in moodlelib.php for ideas about how to&lt;br /&gt;
&lt;br /&gt;
* encode and unencode the arguments your module needs to do the processing&lt;br /&gt;
* how to deal with multiple &amp;quot;actions&amp;quot; for any given module.&lt;br /&gt;
&lt;br /&gt;
In a nutshell, users can send emails to Moodle using special dynamic addresses. These emails can trigger a call to a module function in the form of modulename_process_email($str, $bodyofemail). The $str part will be up to 42 characters of data generated by Moodle (presumably by your own module), and the $bodyofemailpart is the contents of the email (got by reading STDIN - usually generated by the users MUA).&lt;br /&gt;
&lt;br /&gt;
The 42 characters come from the &amp;quot;local part&amp;quot; of an email address (the part before the @ sign) which can have up to 64 chars. Out of those 64 chars, Moodle uses 22 characters, leaving you with 42 characters to encode data.&lt;br /&gt;
&lt;br /&gt;
What do we do with the 22 chars? Four go to the prefix, which we need to let the MTA know to pass the message to our script. Two go to identify the module ID so we know which module has generated the message (and so we dispatch the request to that module). The remaining 16 are a signature (HMAC-MD5-8) we use to authenticate the message.&lt;br /&gt;
&lt;br /&gt;
Forty-two characters isn&#039;t a lot (although it could be the answer to life, the universe, and everything!) so make sure you use those characters wisely.&lt;br /&gt;
&lt;br /&gt;
The most efficient way to encode database IDs in their full range (so that they can be placed in an email address) we have found is base64_encode(pack(&#039;V&#039;,2147483647)), which returns &amp;quot;/ / / / f w = =&amp;quot;. The two trailing &amp;quot;= =&amp;quot; are redundant and you can remove them (you&#039;ll need to reappend them when retrieving your data). Join your parameters as encoded IDs in positional slots for efficiency.&lt;br /&gt;
&lt;br /&gt;
To retrieve your data, use substr() to separate your parameters, and then unpack(&#039;V&#039;,base64_decode($str)). Note that it&#039;ll return a one-element array.&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Using &#039;V&#039; reaches 2147483647, half the range of mySQL&#039;s INT. Additionally, &#039;V&#039; behaves like a signed value, rather than an unsigned, so I suspect there&#039;s a bug in PHP&#039;s documentation of pack().&lt;br /&gt;
&lt;br /&gt;
With each ID taking 6-chars (8 chars if we find a way to use the full range of &#039;V&#039;), you have a limited number of parameters. If you need to encode more information, store it in the DB and send emails that point to your stored data. Remember to cleanup this temporary data after a safe period of time.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Do not try to use variable-width encoding to put IDs, as it&#039;ll work in small installations and break in larger ones.&lt;br /&gt;
&lt;br /&gt;
== Security issues ==&lt;br /&gt;
&lt;br /&gt;
Any code in modulename_process_email() _must_ assume it will see repeat replies and handle them gracefully. The definition of &#039;gracefully&#039; depends on what the code does.&lt;br /&gt;
&lt;br /&gt;
Email servers (MTAs) will sometimes re-transmit a message if they are unsure that the receiving MTA got it -- and sysadmins may sometimes replay a whole email queue if something&#039;s gone wrong. In that case, they email body will be identical, the headers slightly different.&lt;br /&gt;
&lt;br /&gt;
In a different case, the user may &#039;reply&#039; to the message twice. Perhaps in error, perhaps purposefully. What to do depends on the specific scenario.&lt;br /&gt;
&lt;br /&gt;
We /could/ support better protection at the framework level, by keeping track of every reply-to address we send out. We decided against that because (a) the performance impact will be important (b) we want the 1st cut to be lightweight and simple to change in case we need to.&lt;br /&gt;
&lt;br /&gt;
With this the initial implementation, modules should expose functions that handle these &amp;quot;replay&amp;quot; cases correctly. If later we want to expose additional functions, we can add such tracking as an optional thing. It&#039;d be awful to have it across all emails sent from Moodle.&lt;br /&gt;
&lt;br /&gt;
== Experimental email processing, pending merge into 1.9/2.0 ==&lt;br /&gt;
===Module Authors===&lt;br /&gt;
The email interface allows you to let users respond to emails sent via your module and affect change in them. The basic idea is that each email is uniquely identified with an email session that carries with it a simple payload. This payload is stored via database, and cannot be changed by the user. Replies are handled by module code in your lib.php library - modulename_process_email($payload, $body) - which is passed the session payload and the body (with full headers) of the email received, to be parsed as you like. Some utility functions are available as well to help with this.&lt;br /&gt;
&lt;br /&gt;
Here is an outline of the intended use:&lt;br /&gt;
* Before sending an email to a user via the email_to_user() function, the module should check to see if the config variable $CFG-&amp;gt;emailinterface is enabled. (This is off by default)&lt;br /&gt;
* Assuming the email interface is enabled, the function generate_email_verp_address($moduleid, $payload, $userid) should be called to create an &amp;quot;email session&amp;quot;. The payload should include any data you wish to use in your handling routine - such as the id of the user, or what part of the interface he is interacting with. The function will return a string containing the email session id.&lt;br /&gt;
* Call the email_to_user() function as normal, appending the email session id as the 11th parameter. Keep in mind that you will probably also need to change the text or html of the email to point out that the email interface is active.&lt;br /&gt;
* A function contained in the lib.php file of your module, named [modulename]_process_email($payload, $body) should be written. This is the handler function, which is called when an email reply is received. This function can inspect the contents of the payload received, then parse the email body for data. The $body parameter returns the full email, including the headers.&lt;br /&gt;
&lt;br /&gt;
Note that each email can only be replied to once - the email session is destroyed once an email has been received. If you wish to have multiple replies from a user, you will have to create a new session (and new email) every time. The email session table is also regularly pruned, the default settings allow sessions to persist for one month.&lt;br /&gt;
&lt;br /&gt;
The following utility functions are also defined in admin/process_email.php, which can help:&lt;br /&gt;
* get_email_subject($fullemail) - return the subject of an email&lt;br /&gt;
* strip_email_headers($fullemail) - strip all headers off an email&lt;br /&gt;
* email_is_multipart($fullemail) - determine if an email is a multipart message&lt;br /&gt;
* seperate_multipart($multipartmsg) - seperate a multipart email message into an array of parts, each of which has headers and a body.&lt;br /&gt;
* get_multipart_content_type($part) - determine the content-type of a multipart, generally text/plain or text/html.&lt;br /&gt;
* multipart_is_quoted_printable($part) - determine if a email part has been encoded with the quoted-printable encoding - some email clients tend to do this to html.&lt;br /&gt;
* decode_quoted_printable($partdata) - decode a email that has been encoded with quoted-printable encoding - this needs to be run on the data section of a part (strip_email_headers can be used to seperate the headers of a part).&lt;br /&gt;
* strip_email_reply($body, $ishtml, $identifier) - strip all irrelevant lines of an email message based on a unique identifier embedded within the original message. This is used to determine what is user input, and what is irrelevant data the email client has added.&lt;br /&gt;
* strip_email_reply_multi($body, $ishtml, $identifier) - as above, but allowing for multiple sections of possible user input in a single email message.&lt;br /&gt;
&lt;br /&gt;
Examples of use of these functions can be seen in the handler for the forum module. The idea behind the strip reply functions is that the original email will contain a unique identifier, such as a random 10 character string. This is embedded in a line with instructions for the user to write below and above it, e.g:&lt;br /&gt;
  \/ Please put your response here [ABCDEFGHIJ] \/&lt;br /&gt;
  &amp;lt;User Data&amp;gt;&lt;br /&gt;
  /\ Please put your response here [ABCDEFGHIJ] /\&lt;br /&gt;
This is necessary because of the wide differences between webmail and email clients in handling quotes and prefixing dates/times to replied emails. Keep in mind that text emails have an 80-character line width restrictions, which must also include the quote added by the email client, so any line of a text-email with this identifier should be kept to at least 77 characters to avoid wrapping by an email client. This unique identifier can be easily stored in the payload. Multiple input sections are handled similarly - a number is appended to the end of the identifier, e.g. [ABCDEFGHIJ1] to signfiy the first section of input. The strip_email_reply_multi returns an array containing a map from each numbered section it finds to a string containing all data in that section.&lt;br /&gt;
&lt;br /&gt;
===Developer Info===&lt;br /&gt;
The reply-to header is now encoded in base32 instead of base64 to allow for case-insensitive MTA&#039;s. Generate_email_processing_address was left as a backwards-compatibility wrapper, modules should use generate_email_verp_address now instead.&lt;br /&gt;
&lt;br /&gt;
Email sessions have been created to deal with the lack of space avaliable in the header under base32, payloads are stored in a new table mdl_email_sessions, and are identified with a unique base32 key which is embedded in the reply-to header. Each row has a timestamp, and the table is pruned during cleanup cron in admin/cron.php.&lt;br /&gt;
&lt;br /&gt;
Bounce detection is now linked in with the email interface - bounce detection is included in admin/process_email.php. Some new configuration variables have also been created to help configure these changes - $CFG-&amp;gt;emailinterface and $CFG-&amp;gt;emailsessiontime - and both have been added to the server settings admin page.&lt;br /&gt;
&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27324</id>
		<title>Email processing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Email_processing&amp;diff=27324"/>
		<updated>2007-09-26T18:41:18Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* Email confirmation or registration words */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Features ==&lt;br /&gt;
&lt;br /&gt;
Moodle now makes better use of the SMTP protocol and email in general. Most of the benefits result from using a technique known as Variable Envelope Return Path (VERP).&lt;br /&gt;
&lt;br /&gt;
* Works on most modern MTAs (at least on Unix systems).&lt;br /&gt;
* All processing of bounces and replies is secured using HMAC-MD5-8.&lt;br /&gt;
* Bounces are handled correctly and increase a &amp;quot;bad email&amp;quot; score for the user.&lt;br /&gt;
* noreply@host address is now on Reply-to field, avoiding accidental pollution of users address books.&lt;br /&gt;
* noreply@host has an autorresponder&lt;br /&gt;
* Makes it easy for modules to send emails with a signed VERP reply-to.&lt;br /&gt;
* Handles receving of VERP replies: Validates the HMAC-MD5-8 signature and Dispatches the encoded request data to the relevant module&lt;br /&gt;
&lt;br /&gt;
== Moodle configuration ==&lt;br /&gt;
&lt;br /&gt;
Edit config.php to enable bounce handling, and setup Moodle to match your MTA configuration. Here&#039;s how. Uncomment these lines in config.php (if you cannot find them, copy them from config-dist.php):&lt;br /&gt;
&lt;br /&gt;
  // once handlebounces is true, we will be using VERP for the return address of every sent email&lt;br /&gt;
  $CFG-&amp;gt;handlebounces = true;&lt;br /&gt;
  // minimum bounces allowed per user&lt;br /&gt;
  $CFG-&amp;gt;minbounces = 10;&lt;br /&gt;
  // ratio of bad emails to sent emails&lt;br /&gt;
  // if we get more than 20% bounces &lt;br /&gt;
  // for a given user, his/her email is marked bad&lt;br /&gt;
  $CFG-&amp;gt;bounceratio = .20;&lt;br /&gt;
&lt;br /&gt;
Edit the $CFG-&amp;gt;maildomain line and one of the $CFG-&amp;gt;mailprefix lines (the one that matches your MTA).&lt;br /&gt;
&lt;br /&gt;
Make sure your server has a command-line PHP interpreter, and that it is able to connect to mysql (or postgres if relevant). If you are able to run cron.php from the commandline or from crontab, this means PHP is ok.&lt;br /&gt;
&lt;br /&gt;
Edit the process_email.php script to point to the location of your php binary. It will usually be &#039;&#039;/usr/bin/php&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==Email confirmation or registration words==&lt;br /&gt;
*  Students receive a confirmation email when they create a user account.  This text can be found in the lang/?/moodle.php as the emailconfirmation &amp;quot;variable&amp;quot;.&lt;br /&gt;
* Students receive a welcome email when they enroll in a course.  This text can be found in the lang/?/moodle.php file as the welcometocoursetext &amp;quot;variable&amp;quot;.&lt;br /&gt;
*The best way to edit these strings is to go to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit. Once you have done this, hit the &amp;quot;Switch lang directory&amp;quot; button, and do your editing.&lt;br /&gt;
*If you decide to get your hands dirty and work by editing the moodle.php directly, be careful to open the file only in a simple text editor like notepad or wordpad. &lt;br /&gt;
*Tip: Be careful with markup - as you edit, you must use &amp;quot; for things like putting in hyperlinks, titles and targets. You MUST &#039;escape&#039; them by putting a \ before each &amp;quot;. If you don&#039;t the resulting page will appear blank.&lt;br /&gt;
**Use &amp;lt;nowiki&amp;gt;&amp;lt;a href=\&amp;quot;http://www.blah_blah\&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
*** Do not use &amp;lt;nowiki&amp;gt;&amp;lt;a href=&amp;quot;http://www.blah_blah&amp;quot;&amp;gt;click here&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt; &lt;br /&gt;
**Use the \ before target= and title= and other similar codes, anywhere you must use &amp;quot; in the markup.&lt;br /&gt;
*If you feel you must really go the route of editing the moodle.php file directly, save a copy of the file in its own folder (copy and paste the file in the same folder). That way, if it all goes wrong for you, all you have to do is delete the botched file and rename the &#039;copy of moodle.php&#039; back to &#039;moodle.php&#039; and you are back to square one, no harm done!&lt;br /&gt;
*Having said all that, it is best to do all your editing in the web interface by going to Site Administration -&amp;gt; Language editing, and then clicking on the string that you wish to edit.&lt;br /&gt;
&lt;br /&gt;
Make sure &#039;&#039;process_email.php&#039;&#039; is executable by running &amp;quot;chmod ugo+rx process_email.php&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Setup under Postfix ==&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;|&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; and moodle installed under /var/www/moodle we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
== Setup under Qmail ==&lt;br /&gt;
&lt;br /&gt;
Depending on your setup, your aliases will be controlled by one or more of&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;/etc/aliases&#039;&#039;&lt;br /&gt;
* &#039;&#039;/var/qmail/alias/.qmail-PREFIX&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you edit /etc/aliases add a line like this (for a prefix of &#039;mdl&#039;):&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you create /var/qmail/alias/.qmail-PREFIX, just do&lt;br /&gt;
&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-mdl&lt;br /&gt;
  echo &amp;quot;|/var/www/moodle/admin/process_email.php&amp;quot; &amp;gt; /var/qmail/alias/.qmail-noreply&lt;br /&gt;
&lt;br /&gt;
To this three letter prefix, we will add a &#039;-&#039; when sending and receiving messages. For more info, check out the manpage for dot-qmail.&lt;br /&gt;
&lt;br /&gt;
== Setup under Exim ==&lt;br /&gt;
&lt;br /&gt;
Open &#039;&#039;/etc/exim/exim.conf&#039;&#039; and add to trusted_users the user Apache and cron.php run as (usually &amp;quot;www-data&amp;quot; or &amp;quot;nobody&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Add a line to your aliases file. The line should list a 3-letter prefix, to which we&#039;ll add a &#039;+&#039;, and the path of the script. For example for a prefix of &#039;mdl&#039; we have in aliases:&lt;br /&gt;
&lt;br /&gt;
    mdl:     |/var/www/moodle/admin/process_email.php&lt;br /&gt;
    noreply: |/var/www/moodle/admin/process_email.php&lt;br /&gt;
&lt;br /&gt;
If you are using virtualdomains, consult your server administrator for the correct configuration. It probably involves editing transports and mapping your address to a &amp;quot;pipe&amp;quot; transport.&lt;br /&gt;
&lt;br /&gt;
More documentation about Exim can be found [http://www.exim.org/docs.html here]. You may have to tell Exim not to lowercase the local-part.&lt;br /&gt;
&lt;br /&gt;
== Developer info ==&lt;br /&gt;
&lt;br /&gt;
Changed functions:&lt;br /&gt;
&lt;br /&gt;
* email_to_user() will set the envelope sender to a special bounce processing address (based on $CFG settings)&lt;br /&gt;
* email_to_user() will accept (and set) a reply-to header, to be generated by the module calling the function.&lt;br /&gt;
* associated string changes/additions&lt;br /&gt;
&lt;br /&gt;
New functions:&lt;br /&gt;
&lt;br /&gt;
* generate_email_processing_address() - ALWAYS use this to generate the reply-to header. reply-to header will look like this: (LIMIT: 64 chars total) prefix - EXACTLY four chars encodeded, packed, moduleid (0 for core) (2 chars) up to 42 chars for the modules to put anything they want it (can contain userid (or, eg for forum, postids to reply to), or anything really. 42 chars is ABSOLUTE LIMIT) 16 char hash (half an md5) of the first part of the address, together with a site &amp;quot;secret&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* moodle_process_email() - any non-module email processing goes here (currently used for processing bounces)&lt;br /&gt;
&lt;br /&gt;
New files:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/process_email.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This script needs to be called from your MTA for anything starting with the 3 char prefix described above (and optionally, the noreply address).&lt;br /&gt;
&lt;br /&gt;
How does it work? It will break down and unencode the email address into moduleid and validate the half md5 hash, and call $modname_process_email (if it exists). Arguments to these functions are: $modargs (any part of the email address that isn&#039;t the prefix, modid or the hash) and the contents of the email (read from STDIN).&lt;br /&gt;
&lt;br /&gt;
It doubles up as the noreplyaddress autorresponder if you configure it with that address as well. Replying with a friendly &amp;quot;this is not a real email address&amp;quot; message.&lt;br /&gt;
&lt;br /&gt;
== Module Authors ==&lt;br /&gt;
&lt;br /&gt;
Take a look at new functions moodle_process_email() and generate_email_processing_address() in moodlelib.php for ideas about how to&lt;br /&gt;
&lt;br /&gt;
* encode and unencode the arguments your module needs to do the processing&lt;br /&gt;
* how to deal with multiple &amp;quot;actions&amp;quot; for any given module.&lt;br /&gt;
&lt;br /&gt;
In a nutshell, users can send emails to Moodle using special dynamic addresses. These emails can trigger a call to a module function in the form of modulename_process_email($str, $bodyofemail). The $str part will be up to 42 characters of data generated by Moodle (presumably by your own module), and the $bodyofemailpart is the contents of the email (got by reading STDIN - usually generated by the users MUA).&lt;br /&gt;
&lt;br /&gt;
The 42 characters come from the &amp;quot;local part&amp;quot; of an email address (the part before the @ sign) which can have up to 64 chars. Out of those 64 chars, Moodle uses 22 characters, leaving you with 42 characters to encode data.&lt;br /&gt;
&lt;br /&gt;
What do we do with the 22 chars? Four go to the prefix, which we need to let the MTA know to pass the message to our script. Two go to identify the module ID so we know which module has generated the message (and so we dispatch the request to that module). The remaining 16 are a signature (HMAC-MD5-8) we use to authenticate the message.&lt;br /&gt;
&lt;br /&gt;
Forty-two characters isn&#039;t a lot (although it could be the answer to life, the universe, and everything!) so make sure you use those characters wisely.&lt;br /&gt;
&lt;br /&gt;
The most efficient way to encode database IDs in their full range (so that they can be placed in an email address) we have found is base64_encode(pack(&#039;V&#039;,2147483647)), which returns &amp;quot;/ / / / f w = =&amp;quot;. The two trailing &amp;quot;= =&amp;quot; are redundant and you can remove them (you&#039;ll need to reappend them when retrieving your data). Join your parameters as encoded IDs in positional slots for efficiency.&lt;br /&gt;
&lt;br /&gt;
To retrieve your data, use substr() to separate your parameters, and then unpack(&#039;V&#039;,base64_decode($str)). Note that it&#039;ll return a one-element array.&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Using &#039;V&#039; reaches 2147483647, half the range of mySQL&#039;s INT. Additionally, &#039;V&#039; behaves like a signed value, rather than an unsigned, so I suspect there&#039;s a bug in PHP&#039;s documentation of pack().&lt;br /&gt;
&lt;br /&gt;
With each ID taking 6-chars (8 chars if we find a way to use the full range of &#039;V&#039;), you have a limited number of parameters. If you need to encode more information, store it in the DB and send emails that point to your stored data. Remember to cleanup this temporary data after a safe period of time.&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
Do not try to use variable-width encoding to put IDs, as it&#039;ll work in small installations and break in larger ones.&lt;br /&gt;
&lt;br /&gt;
== Security issues ==&lt;br /&gt;
&lt;br /&gt;
Any code in modulename_process_email() _must_ assume it will see repeat replies and handle them gracefully. The definition of &#039;gracefully&#039; depends on what the code does.&lt;br /&gt;
&lt;br /&gt;
Email servers (MTAs) will sometimes re-transmit a message if they are unsure that the receiving MTA got it -- and sysadmins may sometimes replay a whole email queue if something&#039;s gone wrong. In that case, they email body will be identical, the headers slightly different.&lt;br /&gt;
&lt;br /&gt;
In a different case, the user may &#039;reply&#039; to the message twice. Perhaps in error, perhaps purposefully. What to do depends on the specific scenario.&lt;br /&gt;
&lt;br /&gt;
We /could/ support better protection at the framework level, by keeping track of every reply-to address we send out. We decided against that because (a) the performance impact will be important (b) we want the 1st cut to be lightweight and simple to change in case we need to.&lt;br /&gt;
&lt;br /&gt;
With this the initial implementation, modules should expose functions that handle these &amp;quot;replay&amp;quot; cases correctly. If later we want to expose additional functions, we can add such tracking as an optional thing. It&#039;d be awful to have it across all emails sent from Moodle.&lt;br /&gt;
&lt;br /&gt;
== Experimental email processing, pending merge into 1.9/2.0 ==&lt;br /&gt;
===Module Authors===&lt;br /&gt;
The email interface allows you to let users respond to emails sent via your module and affect change in them. The basic idea is that each email is uniquely identified with an email session that carries with it a simple payload. This payload is stored via database, and cannot be changed by the user. Replies are handled by module code in your lib.php library - modulename_process_email($payload, $body) - which is passed the session payload and the body (with full headers) of the email received, to be parsed as you like. Some utility functions are available as well to help with this.&lt;br /&gt;
&lt;br /&gt;
Here is an outline of the intended use:&lt;br /&gt;
* Before sending an email to a user via the email_to_user() function, the module should check to see if the config variable $CFG-&amp;gt;emailinterface is enabled. (This is off by default)&lt;br /&gt;
* Assuming the email interface is enabled, the function generate_email_verp_address($moduleid, $payload, $userid) should be called to create an &amp;quot;email session&amp;quot;. The payload should include any data you wish to use in your handling routine - such as the id of the user, or what part of the interface he is interacting with. The function will return a string containing the email session id.&lt;br /&gt;
* Call the email_to_user() function as normal, appending the email session id as the 11th parameter. Keep in mind that you will probably also need to change the text or html of the email to point out that the email interface is active.&lt;br /&gt;
* A function contained in the lib.php file of your module, named [modulename]_process_email($payload, $body) should be written. This is the handler function, which is called when an email reply is received. This function can inspect the contents of the payload received, then parse the email body for data. The $body parameter returns the full email, including the headers.&lt;br /&gt;
&lt;br /&gt;
Note that each email can only be replied to once - the email session is destroyed once an email has been received. If you wish to have multiple replies from a user, you will have to create a new session (and new email) every time. The email session table is also regularly pruned, the default settings allow sessions to persist for one month.&lt;br /&gt;
&lt;br /&gt;
The following utility functions are also defined in admin/process_email.php, which can help:&lt;br /&gt;
* get_email_subject($fullemail) - return the subject of an email&lt;br /&gt;
* strip_email_headers($fullemail) - strip all headers off an email&lt;br /&gt;
* email_is_multipart($fullemail) - determine if an email is a multipart message&lt;br /&gt;
* seperate_multipart($multipartmsg) - seperate a multipart email message into an array of parts, each of which has headers and a body.&lt;br /&gt;
* get_multipart_content_type($part) - determine the content-type of a multipart, generally text/plain or text/html.&lt;br /&gt;
* multipart_is_quoted_printable($part) - determine if a email part has been encoded with the quoted-printable encoding - some email clients tend to do this to html.&lt;br /&gt;
* decode_quoted_printable($partdata) - decode a email that has been encoded with quoted-printable encoding - this needs to be run on the data section of a part (strip_email_headers can be used to seperate the headers of a part).&lt;br /&gt;
* strip_email_reply($body, $ishtml, $identifier) - strip all irrelevant lines of an email message based on a unique identifier embedded within the original message. This is used to determine what is user input, and what is irrelevant data the email client has added.&lt;br /&gt;
* strip_email_reply_multi($body, $ishtml, $identifier) - as above, but allowing for multiple sections of possible user input in a single email message.&lt;br /&gt;
&lt;br /&gt;
Examples of use of these functions can be seen in the handler for the forum module. The idea behind the strip reply functions is that the original email will contain a unique identifier, such as a random 10 character string. This is embedded in a line with instructions for the user to write below and above it, e.g:&lt;br /&gt;
  \/ Please put your response here [ABCDEFGHIJ] \/&lt;br /&gt;
  &amp;lt;User Data&amp;gt;&lt;br /&gt;
  /\ Please put your response here [ABCDEFGHIJ] /\&lt;br /&gt;
This is necessary because of the wide differences between webmail and email clients in handling quotes and prefixing dates/times to replied emails. Keep in mind that text emails have an 80-character line width restrictions, which must also include the quote added by the email client, so any line of a text-email with this identifier should be kept to at least 77 characters to avoid wrapping by an email client. This unique identifier can be easily stored in the payload. Multiple input sections are handled similarly - a number is appended to the end of the identifier, e.g. [ABCDEFGHIJ1] to signfiy the first section of input. The strip_email_reply_multi returns an array containing a map from each numbered section it finds to a string containing all data in that section.&lt;br /&gt;
&lt;br /&gt;
===Developer Info===&lt;br /&gt;
The reply-to header is now encoded in base32 instead of base64 to allow for case-insensitive MTA&#039;s. Generate_email_processing_address was left as a backwards-compatibility wrapper, modules should use generate_email_verp_address now instead.&lt;br /&gt;
&lt;br /&gt;
Email sessions have been created to deal with the lack of space avaliable in the header under base32, payloads are stored in a new table mdl_email_sessions, and are identified with a unique base32 key which is embedded in the reply-to header. Each row has a timestamp, and the table is pruned during cleanup cron in admin/cron.php.&lt;br /&gt;
&lt;br /&gt;
Bounce detection is now linked in with the email interface - bounce detection is included in admin/process_email.php. Some new configuration variables have also been created to help configure these changes - $CFG-&amp;gt;emailinterface and $CFG-&amp;gt;emailsessiontime - and both have been added to the server settings admin page.&lt;br /&gt;
&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=admin/environment/php_extension/iconv&amp;diff=25880</id>
		<title>admin/environment/php extension/iconv</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=admin/environment/php_extension/iconv&amp;diff=25880"/>
		<updated>2007-08-12T13:05:41Z</updated>

		<summary type="html">&lt;p&gt;Matm: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;To install/enable iconv: &lt;br /&gt;
&lt;br /&gt;
#Open the &#039;&#039;php.ini&#039;&#039; file found in the &#039;&#039;moodle/apache/bin&#039;&#039; folder&lt;br /&gt;
#Find the line: &amp;lt;code&amp;gt;;extension=php_iconv.dll&amp;lt;/code&amp;gt;&lt;br /&gt;
#Remove the &amp;lt;code&amp;gt;;&amp;lt;/code&amp;gt; at the beginning of the line&lt;br /&gt;
#Restart apache for the change to take effect.&lt;br /&gt;
{{stub}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Environment|PHP]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Installation_FAQ&amp;diff=25605</id>
		<title>Installation FAQ</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Installation_FAQ&amp;diff=25605"/>
		<updated>2007-08-03T18:48:12Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* Fatal error allowed memory size exhausted. How do I increase my php memory limit? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{FAQ}}&lt;br /&gt;
&lt;br /&gt;
==PHP - is it installed and what version do I have?==&lt;br /&gt;
&lt;br /&gt;
Make a new file on your web site called &#039;&#039;info.php&#039;&#039;, containing the following text, and call it from your browser:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;?PHP phpinfo() ?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If nothing happens then you don&#039;t have PHP installed or your webserver is not configured to handle .php files properly. See the installation docs for some information about where to download it for your computer. See the [[phpinfo]] page for details about the content of this page.&lt;br /&gt;
&lt;br /&gt;
== System information needed for Installation Forum ==&lt;br /&gt;
When posting questions to the installation forum, try to provide as much background information as possible about your moodle system. Use this template to copy and paste into your post:&lt;br /&gt;
* Server OS name (version also if possible): &lt;br /&gt;
* Browser name (version also if possible):&lt;br /&gt;
* Moodle version:&lt;br /&gt;
* Moodle config.php attached?(Y/N):&lt;br /&gt;
* Phpinfo attached? (Y/N):&lt;br /&gt;
&lt;br /&gt;
For the last two items, try to include the following in your post as an attachment:&lt;br /&gt;
* A copy of your phpinfo output as shown in your browser (see the instructions above for an explanation of how to obtain this).&lt;br /&gt;
* A copy of the Moodle configuration file. This is located in the directory moodle and is named config.php&lt;br /&gt;
&lt;br /&gt;
Copy and paste both of these into a single text file (using vi, Notepad, etc) and attach this to your post.&lt;br /&gt;
&lt;br /&gt;
If you cannot provide your phpinfo, try to copy &amp;amp; paste and complete these in your post:&lt;br /&gt;
* Apache version:&lt;br /&gt;
* MySQL version:&lt;br /&gt;
* PHP version:&lt;br /&gt;
&lt;br /&gt;
For installation on web hosting accounts: contact your support desk who should be able to tell you this information.&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;Security Warning&#039;&#039;&#039;: Make sure you edit any files and delete any passwords before posting onto the forum.&lt;br /&gt;
&lt;br /&gt;
==What &amp;amp; where are Moodle&#039;s configuration settings stored?==&lt;br /&gt;
Configuration settings are stored in the config.php file stored in your moodle folder. This file is created during the installation process. If there is a problem and the installation cannot create the file, you can try creating it manually from the [[Configuration file]] docs. Please remember that manually editing the file is not recommended and may lead to blank pages, especially if there are additional spaces and/or lines after the final php closing tag &amp;quot;?&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==Running a health check==&lt;br /&gt;
Moodle contains a script that will help identify common php and webserver configuration problems as well as configuration problems. It is a good idea to run this script to check if you are having post-installation problems. Use your browser to run this file:&lt;br /&gt;
&lt;br /&gt;
 http://www.mymoodle.com/moodle/admin/health.php&lt;br /&gt;
&lt;br /&gt;
Change the above line if you have installed moodle in the webroot instead of a folder inside the webroot.&lt;br /&gt;
&lt;br /&gt;
==Downloading previous releases of Moodle==&lt;br /&gt;
* &#039;&#039;&#039;Generic Packages&#039;&#039;&#039;: If your server does not meet the [[Installing_Moodle#Requirements | requirements]] for the current version of Moodle, you can download previous releases by using this URL:&lt;br /&gt;
 http://download.moodle.org/stable[version_number] &lt;br /&gt;
:For example: to download Moodle version 1.5, use http://download.moodle.org/stable15. You&#039;ll see a directory tree with the files displayed. Click on the one you want and download as normal - if you require the latest update of the version, scroll to the end of the list and download the &amp;quot;moodle-latest&amp;quot; file. Changes made in the version in the last month are listed in the &amp;quot;CHANGES&amp;quot; file. The files contain Moodle code and are not the Windows or Mac packages - so you need to have a webserver, a database server and PHP already installed. The earliest version available is Moodle 1.3.&lt;br /&gt;
* &#039;&#039;&#039;Windows Packages&#039;&#039;&#039;: To download previous releases of the Moodle packages for Windows, use this URL:&lt;br /&gt;
 http://download.moodle.org/windows/MoodleWindowsInstaller-latest-[version_number].zip&lt;br /&gt;
* &#039;&#039;&#039;Mac Packages&#039;&#039;&#039;: To download previous releases of the Mac pacakges, use either of these URLs (depending on whether you need the Intel or PPC package):&lt;br /&gt;
 http://download.moodle.org/macosx/Moodle4Mac-Intel-[version_number].dmg&lt;br /&gt;
 http://download.moodle.org/macosx/Moodle4Mac-PPC-[version_number}.dmg&lt;br /&gt;
* &#039;&#039;&#039;Using CVS&#039;&#039;&#039;: You can also use CVS to download older releases and incremental releases of the Moodle generic packages, e.g. Moodle 1.5.4 - see the [[CVS_for_Administrators | CVS documentation]].&lt;br /&gt;
&lt;br /&gt;
== How to enable and check PHP error logs==&lt;br /&gt;
PHP can be set up to log errors in a variety of different ways: two of these involve the use of the php.ini file and the ini_set command. &lt;br /&gt;
* &#039;&#039;&#039;Using the php.ini file&#039;&#039;&#039;: The log settings are contained in the php.ini file stored on the server. If you don&#039;t know where that is, edit your Moodle &#039;&#039;config.php&#039;&#039; and add the following as the second line&lt;br /&gt;
&lt;br /&gt;
  phpinfo();&lt;br /&gt;
&lt;br /&gt;
:then reload the web page. Look for the entry &#039;&#039;&#039;Configuration File (php.ini) Path&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
:When you have located php.ini open it in your favorite text editor. Find the &#039;&#039;&#039;Error handling and logging&#039;&#039;&#039; section of the php.ini file. Make sure that both &#039;&#039;&#039;display_errors = On&#039;&#039;&#039;, &#039;&#039;&#039;display_startup_errors = On&#039;&#039;&#039; and &#039;&#039;&#039;log_errors = On&#039;&#039;&#039; are present and uncommented. Check the value of &#039;&#039;&#039;error_log&#039;&#039;&#039; - this tells you the location of the file errors are logged to. If it is commented out then errors will be sent to the web server error log file. Remember, if you make any changes to this file you will need to restart the web server (or just reboot the server).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Using ini_set commands&#039;&#039;&#039;: If you are using Moodle 1.8 or higher, the previous steps are not enough. In those versions error logging parameters are dependant on certain administrative settings that you specify in the debugging section. The problem is that if you can&#039;t access the administrative pages, you can&#039;t set the debugging options. So the only way to modify them is by adding the following lines to your config.php file, just before the last line (the one containing a single&#039;?&amp;gt;&#039; only):&lt;br /&gt;
&lt;br /&gt;
  ini_set (&#039;display_errors&#039;, &#039;on&#039;);&lt;br /&gt;
  ini_set (&#039;log_errors&#039;, &#039;on&#039;);&lt;br /&gt;
  ini_set (&#039;display_startup_errors&#039;, &#039;on&#039;);&lt;br /&gt;
&lt;br /&gt;
:This will enable the same settings specified above even if Moodle sets them otherwise. &lt;br /&gt;
:&#039;&#039;&#039;Important&#039;&#039;&#039;: Remember to put them just before the last line of config.php.&lt;br /&gt;
&lt;br /&gt;
==Any text I add with an apostrophe (&#039;) or a quote (&amp;quot;) causes errors or comes up with a slash added==&lt;br /&gt;
&lt;br /&gt;
Problems caused by apostrophes are caused by incorrect &amp;quot;magic quotes&amp;quot; settings. Moodle requires the following settings in the php.ini file (which are usually the default):&lt;br /&gt;
&lt;br /&gt;
 magic_quotes_gpc = On&lt;br /&gt;
 magic_quotes_runtime = Off&lt;br /&gt;
&lt;br /&gt;
Please see [[Installing Moodle]] for more details.&lt;br /&gt;
&lt;br /&gt;
==Email copies are not being sent from my forums==&lt;br /&gt;
&lt;br /&gt;
You &#039;&#039;must&#039;&#039; set up cron properly if you want Moodle to send out automatic email from forums, assignments etc. This same process also performs a number of clean-up tasks such as deleting old unconfirmed users, unenrolling old students and so on.&lt;br /&gt;
&lt;br /&gt;
Basically, you need to set up a process to regularly call the script &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;http://yoursite/admin/cron.php&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;. Please refer to the [[Cron|cron instructions]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tip:&#039;&#039;&#039; Try the default setting in Moodle variables page. Leave the smtphost blank. This will be acceptable for the majority of users.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tip:&#039;&#039;&#039; Make sure that allowuseremailcharset in Administration &amp;gt; Configuration &amp;gt; Variables &amp;gt; Mail is set to No. Setting this to Yes might cause this problem in some versions of Moodle.&lt;br /&gt;
&lt;br /&gt;
==Error: database connection failed==&lt;br /&gt;
&lt;br /&gt;
If you get errors like &amp;quot;database connection failed&amp;quot; or &amp;quot;could not connect to the database you specified&amp;quot;, here are some possible reasons and some possible solutions.&lt;br /&gt;
&lt;br /&gt;
* Your &#039;&#039;&#039;database server&#039;&#039;&#039; isn&#039;t installed or running. To check this for MySQL try typing the following command line&lt;br /&gt;
 $telnet database_host_name 3306&lt;br /&gt;
:You should get a cryptic response which includes the version number of the MySQL server. &lt;br /&gt;
* If you are attempting to run &#039;&#039;&#039;two instances of Moodle on different ports&#039;&#039;&#039;, use the ip address of the host (not localhost) in the $CFG-&amp;gt;dbhost setting, e.g. $CFG-&amp;gt;dbhost = 127.0.0.1:3308.&lt;br /&gt;
* You don&#039;t have the &#039;&#039;&#039;PHP mysql or postgresql extensions&#039;&#039;&#039; installed (please refer to FAQ re. whether PHP is installed).&lt;br /&gt;
* You haven&#039;t created a &#039;&#039;&#039;Moodle database and assigned a user&#039;&#039;&#039; with the correct privileges to access it. &lt;br /&gt;
* The &#039;&#039;&#039;Moodle database settings&#039;&#039;&#039; are incorrect. The database name, database user or database user password in your Moodle configuration file &#039;&#039;config.php&#039;&#039; are incorrect. Use phpMyAdmin to set up and check your MySQL installation.&lt;br /&gt;
* Check that there are &#039;&#039;&#039;no apostrophes or non-alphabetic letters&#039;&#039;&#039; in your MySQL username or password.&lt;br /&gt;
* You are using MySQL version 4.1 or higher but the PHP MySQL extension is pre-4.1 (check in your phpinfo output). In this case the &#039;&#039;&#039;default password hashing algorithm&#039;&#039;&#039; is incompatible with that available in the PHP mysql extension versions 4.x.x. Use these MySQL commands to change the passwords to the old format:&lt;br /&gt;
&lt;br /&gt;
 mysql&amp;gt;SET PASSWORD FOR &#039;root&#039;@&#039;localhost&#039; = OLD_PASSWORD(&#039;password&#039;);&lt;br /&gt;
 mysql&amp;gt;SET PASSWORD FOR &#039;moodleuser&#039;@&#039;localhost&#039; = OLD_PASSWORD(&#039;password&#039;);&lt;br /&gt;
&lt;br /&gt;
:Also, consider upgrading your PHP MySQL extension. See [http://dev.mysql.com/doc/mysql/en/old-client.html this MySQL document] for further information on how to deal with this problem.&lt;br /&gt;
* You are using Fedora core 3 or some other Linux system with &#039;&#039;&#039;SELinux installed&#039;&#039;&#039; and enabled. See the following URL for information on how to disable SELinux: http://fedora.redhat.com/projects/selinux/&lt;br /&gt;
* Mac OSX users -- if you are running MySQL on a Mac OSX, try changing &#039;&#039;&#039;$CFG-&amp;gt;dbhost&#039;&#039;&#039; from &#039;localhost&#039; to &#039;127.0.0.1&#039;&lt;br /&gt;
&#039;&#039;&#039;See also&#039;&#039;&#039;: MySQL page on [http://dev.mysql.com/doc/refman/5.0/en/common-errors.html common errors] which lists several possible scenarios for connection failure, with advice on how to fix the problems.&lt;br /&gt;
&lt;br /&gt;
==I can&#039;t log in - I just stay stuck on the login screen==&lt;br /&gt;
&lt;br /&gt;
The most common cause for this is that your own computer (not your Moodle server) has a firewall that is stripping referrer information from the browser. Here are some instructions for fixing [http://service1.symantec.com/SUPPORT/nip.nsf/46f26a2d6dafb0a788256bc7005c3fa3/b9b47ad7eddd343b88256c6b006a85a8?OpenDocument&amp;amp;src=bar_sch_nam Norton firewall products].&lt;br /&gt;
&lt;br /&gt;
The server admin can also fix this for everyone by changing the &#039;&#039;secureforms&#039;&#039; variable to &#039;No&#039; in the security section of Administration &amp;gt;&amp;gt; Configuration &amp;gt;&amp;gt; [[admin/config|Variables]].&lt;br /&gt;
&lt;br /&gt;
Another possible cause of this problem is that sessions are not configured properly on the server. You can test this by calling the script &amp;lt;nowiki&amp;gt;http://yourserver/moodle/lib/session-test.php&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you are still having problems, read the [[Can_not_log_in | Cannot log in]] page.&lt;br /&gt;
&lt;br /&gt;
==I can&#039;t log in with message &amp;quot;Please verify that the current setting of session.save_path is correct&amp;quot; ==&lt;br /&gt;
&lt;br /&gt;
This error occurs when PHP is having problems saving its session files. You may also see these other error messages displayed on the screen or in your log files:&lt;br /&gt;
&lt;br /&gt;
 Warning: Unknown: open(some-path/sessions/sess_acbf942a7399db3489ffa910e35d5242, O_RDWR)&lt;br /&gt;
 failed: Permission denied (13) in Unknown on line 0&lt;br /&gt;
&lt;br /&gt;
 Warning: Unknown(): open(some-path/sessions/sess_acbf942a7399db3489ffa910e35d5242, O_RDWR) &lt;br /&gt;
 failed: No space left on device (28) in Unknown on line 0&lt;br /&gt;
&lt;br /&gt;
 Warning: Unknown: Failed to write session data (files). Please verify that the current &lt;br /&gt;
 setting of session.save_path is correct (some-path/sessions) in Unknown on line 0 &lt;br /&gt;
&lt;br /&gt;
To temporarily bypass these errors, &#039;&#039;&#039;use database sessions&#039;&#039;&#039; by editing your [[Configuration_file | moodle configuration file]] and adding this line:&lt;br /&gt;
&lt;br /&gt;
 $CFG-&amp;gt;dbsessions = true;&lt;br /&gt;
&lt;br /&gt;
Database sessions may overload your mysql database and are not ideal in a shared hosting environment, so if this solves the problem, you can start fixing the problem as follows:&lt;br /&gt;
* Check &#039;&#039;&#039;access rights&#039;&#039;&#039;. The session.save_path should be accessible by the apache user. Try this command:&lt;br /&gt;
&lt;br /&gt;
 chown -R apache:apache some-path/sessions&lt;br /&gt;
&lt;br /&gt;
:This assumes that &#039;apache&#039; is the name of the user your webserver runs under - it could also be &#039;nobody&#039;.&lt;br /&gt;
* Check the &#039;&#039;&#039;permissions&#039;&#039;&#039; to the directory that PHP is trying to save to (session.save_path = some-path/sessions). Set the permissions initially to 0777 (everyone read, write, execute) with this command:&lt;br /&gt;
&lt;br /&gt;
 chmod -R 0777 some-path/sessions&lt;br /&gt;
&lt;br /&gt;
:If this fixes the problem, reduce the permissions (700 is recommended).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;See also&#039;&#039;&#039;: Session problems can be specific to your server environment. As an example, see [http://moodle.org/mod/forum/discuss.php?d=55925#254596 this forum discussion] about session problems with Lycos hosting.&lt;br /&gt;
&lt;br /&gt;
==I log in but the login link doesn&#039;t change. I am logged in and can navigate freely.==&lt;br /&gt;
&lt;br /&gt;
Make sure the URL in your &amp;lt;code&amp;gt;$CFG-&amp;gt;wwwroot&amp;lt;/code&amp;gt; setting is exactly the same as the one you are actually using to access the site.&lt;br /&gt;
&lt;br /&gt;
==I keep getting this error: A server error that affects your login session was detected.==&lt;br /&gt;
&lt;br /&gt;
Please refer to the Using Moodle forum discussion [http://moodle.org/mod/forum/discuss.php?d=73716 A server error that affects your login session was detected. Please login again or restart your browser.].&lt;br /&gt;
&lt;br /&gt;
==I keep getting this error: Failed opening required &#039;/web/moodle/lib/setup.php&#039;==&lt;br /&gt;
&lt;br /&gt;
In your &#039;&#039;config.php&#039;&#039;, the setting that you use for the dirroot variable must be the complete path from the root of your server&#039;s hard drive.&lt;br /&gt;
&lt;br /&gt;
Sometimes people only use the path from their home directory, or relative to the root of the web server directory.&lt;br /&gt;
&lt;br /&gt;
==My pages show fatal errors such as : Parse error, call to undefined function: get_string()==&lt;br /&gt;
&lt;br /&gt;
If you see errors like:&lt;br /&gt;
&lt;br /&gt;
 Parse error: parse error, unexpected T_VARIABLE in /path/to/moodle/config.php on line 94 &lt;br /&gt;
 Fatal error: Call to undefined function: get_string() in /path/to/moodle/mod/resource/lib.php&lt;br /&gt;
 on line 11&lt;br /&gt;
&lt;br /&gt;
then you have probably left out a semi-colon or closing quote from a line in &#039;&#039;config.php&#039;&#039; (previous to line 94).&lt;br /&gt;
&lt;br /&gt;
Another possibility is that you edited &#039;&#039;config.php&#039;&#039; in a program like Word and saved it as a HTML web page, instead of using a plain text editor like Notepad.&lt;br /&gt;
&lt;br /&gt;
Another thing to check, particularly if you are using 3rd party modules or plugins, is whether any of the php scripts use short open tags (&amp;lt;? ?&amp;gt;) instead of proper ones (&amp;lt;?php ?&amp;gt;). Short tags are bad for various reasons, so first contact the author of that extension to tell them about the problem. Then either replace short tags with conventional ones, or set this line in php.ini:&lt;br /&gt;
&lt;br /&gt;
 short_open_tag = On&lt;br /&gt;
&lt;br /&gt;
You should never find short tags in core moodle code. If you do, please file a bug in the bug tracker.&lt;br /&gt;
&lt;br /&gt;
==Serious Error! Could not set up the site!==&lt;br /&gt;
&lt;br /&gt;
Please refer to the Using Moodle forum discussion [http://moodle.org/mod/forum/discuss.php?d=32071 Serious Error! Could not set up the site!].&lt;br /&gt;
&lt;br /&gt;
==Uploaded files give &amp;quot;File not found&amp;quot;==&lt;br /&gt;
&lt;br /&gt;
For example: Not Found: The requested URL /moodle/file.php/2/myfile.jpg was not found on this server.&lt;br /&gt;
&lt;br /&gt;
Your web server needs to be configured to allow the part of the URL after a script name to be passed directly to the script. This is usually enabled in Apache 1, but is usually disabled by default in Apache 2. To turn it on, add this line to your &#039;&#039;httpd.conf&#039;&#039;, or to a &#039;&#039;.htaccess&#039;&#039; file in your local directory (see [[Installing Moodle]] for more details):&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;AcceptPathInfo&#039;&#039;&#039; on&lt;br /&gt;
&lt;br /&gt;
Note, this will ONLY work for Apache versions 2.x.&lt;br /&gt;
&lt;br /&gt;
If you are not using Apache 2 and you still have this problem (unlikely) then you can switch Moodle to use an alternative method. The disadvantages are a slight loss of performance for your users and you won&#039;t be able to use relative links within HTML resources.&lt;br /&gt;
&lt;br /&gt;
To use this alternative method, you should change the &#039;&#039;slasharguments&#039;&#039; variable in the Operating System section of Administration &amp;gt;&amp;gt; Configuration &amp;gt;&amp;gt; [[admin/config|Variables]]. You should now be able to access your uploaded files.&lt;br /&gt;
&lt;br /&gt;
==When I go to the admin page, I get told to make dirroot blank!==&lt;br /&gt;
&lt;br /&gt;
If you see errors like this:&lt;br /&gt;
&lt;br /&gt;
 Please fix your settings in config.php: &lt;br /&gt;
 You have: $CFG-&amp;gt;dirroot = &amp;quot;/home/users/fred/public_html/moodle&amp;quot;; &lt;br /&gt;
 but it should be: $CFG-&amp;gt;dirroot = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
then you have encountered a small bug that occurs on some servers. The problem is with the error-checking mechanism, not with your actual path. To fix it, find this line (line 66) in the file &#039;&#039;admin/index.php&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
 if ($dirroot != $CFG-&amp;gt;dirroot) {&lt;br /&gt;
&lt;br /&gt;
and change it to this:&lt;br /&gt;
&lt;br /&gt;
 if (!empty($dirroot) and $dirroot != $CFG-&amp;gt;dirroot) {&lt;br /&gt;
&lt;br /&gt;
==When trying to add a resource I receive error messages==&lt;br /&gt;
&lt;br /&gt;
Assuming you are using Apache, then it&#039;s quite likely that your setting in &#039;&#039;config.php&#039;&#039; for &amp;lt;code&amp;gt;$CFG-&amp;gt;wwwroot&amp;lt;/code&amp;gt; is different from the actual URL you are using to access the site. Also try turning off the &#039;&#039;secureforms&#039;&#039; variable in the security section of Administration &amp;gt;&amp;gt; Configuration &amp;gt;&amp;gt; [[admin/config|Variables]].&lt;br /&gt;
&lt;br /&gt;
==Why are all my pages blank?==&lt;br /&gt;
&lt;br /&gt;
Check the dirroot variable in &#039;&#039;config.php&#039;&#039;. You must use complete, absolute pathnames e.g.&lt;br /&gt;
&lt;br /&gt;
 $CFG-&amp;gt;dirroot = &amp;quot;d:\inetpub\sites\www.yoursite.com\web\moodle&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
Another reason might be that PHP has not been configured to support MySQL. This is common on Redhat and OpenBSD installations. In this case, an error is generated, but since error displays are often disabled by default, all that is seen on the browser is a blank screen. To enable PHP error displays, set these lines in your &#039;&#039;php.ini&#039;&#039; file and reload the web page.&lt;br /&gt;
&lt;br /&gt;
 display_errors = On&lt;br /&gt;
 display_startup_errors = On&lt;br /&gt;
&lt;br /&gt;
To determine if MySQL support is your problem, insert this as the second line in your &#039;&#039;config.php&#039;&#039; file&lt;br /&gt;
&lt;br /&gt;
 phpinfo();&lt;br /&gt;
&lt;br /&gt;
then reload the web page. Examine the output closely to see if MySQL is supported. If not look for a package you are missing.&lt;br /&gt;
&lt;br /&gt;
== Why is a particular page blank or incomplete? ==&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Check your web server log files!!&#039;&#039;&#039; &lt;br /&gt;
:If a particular page is blank or incomplete (it doesn&#039;t display the footer), before you do anything else [[Installation_FAQ#How_to_enable_and_check_PHP_error_logs | check your error logs]]. Having established that PHP error logging is working, reproduce the error. Immediately check the error log file right at the end. Hopefully you will see a PHP error message at or very near the end of the file. This may solve your problem directly or makes it a lot easier to diagnose the problem in the Moodle forums.&lt;br /&gt;
&lt;br /&gt;
*If you are &#039;&#039;&#039;upgrading to a new version of Moodle&#039;&#039;&#039;, check that you do not have an old version of a non-standard block or module installed. Remove any such blocks or modules installed remove them using the admin settings page and start the install process again.&lt;br /&gt;
&lt;br /&gt;
*If you &#039;&#039;&#039;do not see any blocks listed&#039;&#039;&#039;, turn editing on and remove any blocks that you have added to that page and try reloading.&lt;br /&gt;
&lt;br /&gt;
==Installation hangs when setting-up database tables==&lt;br /&gt;
*Sometimes the installation will hang when setting up tables. This will be an abrupt hang with half the page displayed in the browser and/or other outputs removed, e.g. the “Scroll to continue” link is displayed but no “Continue” button is there. If this is the case, it is usually a mysql error and not a php error. Check that there is no limit placed on your mysql database, e.g. a &amp;quot;questions&amp;quot; limit.&lt;br /&gt;
&lt;br /&gt;
*If the install is on a webhost, adding the following line to the .htaccess file in the moodle directory has been known to solve the problem.&lt;br /&gt;
 AddType x-mapp-php5 .php&lt;br /&gt;
&lt;br /&gt;
*Try also renaming the .htaccess file so that it is disabled.&lt;br /&gt;
&lt;br /&gt;
*You may also want to look and see if you&#039;ve customized any of your code.  Look at the last successful table, and then look at the block, mod, or other code that is referenced by that table.  For example, if your install hangs and continues to say that the forum tables were successful as the last message, look at /mod/forum/ for any custom code.  If you have customized code, backup those files and replace with the correct files.  You can then restart the install by renaming config.php or reinstalling your database from the backup.  If your install is successful, you can make your code changes back into the stock Moodle code.&lt;br /&gt;
&lt;br /&gt;
*It may also be that the &amp;quot;memory_limit&amp;quot; in your php.ini is set too low. Please check your php.ini file and allocate at least 40MB, as recommended, as the maximum amount of memory a script may consume (ver 1.8).&lt;br /&gt;
&lt;br /&gt;
==Why can&#039;t I upload a new image into my profile?==&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t see anything on your user profile pages to let you upload user images then it&#039;s usually because GD is not enabled on your server. GD is a library that allows image processing.&lt;br /&gt;
&lt;br /&gt;
1. Make sure &#039;&#039;&#039;GD has been included in your PHP installation&#039;&#039;&#039;. You can check this by going into Administration &amp;gt;&amp;gt; Configuration &amp;gt;&amp;gt; [[Variables]] and looking for the gdversion setting. This setting is chosen automatically every time you visit that page. If it shows GD version 1 or version 2 then everything should be fine. Save that configuration page and go back to your user profile.&lt;br /&gt;
&lt;br /&gt;
2. If Moodle thinks GD is not installed, then you will need to &#039;&#039;&#039;install the GD library&#039;&#039;&#039;. &lt;br /&gt;
*On Unix you may need to re-compile PHP with arguments something like this:&lt;br /&gt;
&lt;br /&gt;
 ./configure --with-apxs=/usr/local/apache/bin/apxs --with-xml --with-gd &lt;br /&gt;
 --with-jpeg-dir=/usr/local --with-png-dir=/usr --with-ttf --enable-gd-native-ttf &lt;br /&gt;
 --enable-magic-quotes --with-mysql --enable-sockets --enable-track-vars &lt;br /&gt;
 --enable-versioning --with-zlib&lt;br /&gt;
&lt;br /&gt;
* On Windows this is usually a matter of &amp;quot;turning on&amp;quot; the extension in PHP by editing your php.ini file. To do this remove the semicolon for the php_gd2.dll extension - check that this file is actually present in your php extensions  folder first (search your php.ini for extension_dir to determine where this points to on your hard disk). You should then have a line that looks like this:&lt;br /&gt;
 extension=php_gd2.dll&lt;br /&gt;
&lt;br /&gt;
:Windows users should see the [[Installing AMP|installation instructions]] for further help. &lt;br /&gt;
&lt;br /&gt;
3. Remember to &#039;&#039;&#039;restart your webserver&#039;&#039;&#039; (if possible) and re-visit the Moodle configuration page after making any changes to PHP so it can pick up the correct version of GD.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;See also&#039;&#039;&#039;: Using Moodle forum discussion [http://moodle.org/mod/forum/discuss.php?d=44271 Profile pictures] for additional information.&lt;br /&gt;
&lt;br /&gt;
==Why do I keep getting error messages about &amp;quot;headers already sent&amp;quot;?==&lt;br /&gt;
&lt;br /&gt;
If you see errors like this:&lt;br /&gt;
&lt;br /&gt;
 Warning: Cannot add header information - headers already sent by &lt;br /&gt;
 (output started at /webs/moodle/config.php:87) in /webs/moodle/lib/moodlelib.php &lt;br /&gt;
 on line 1322 &lt;br /&gt;
&lt;br /&gt;
 Warning: Cannot add header information - headers already sent by &lt;br /&gt;
 (output started at /webs/moodle/config.php:87) in /webs/moodle/lib/moodlelib.php &lt;br /&gt;
 on line 1323 &lt;br /&gt;
&lt;br /&gt;
 Warning: Cannot add header information - headers already sent by &lt;br /&gt;
 (output started at /webs/moodle/config.php:87) in /webs/moodle/login/index.php &lt;br /&gt;
 on line 54&lt;br /&gt;
&lt;br /&gt;
you have blank lines or spaces after the final &amp;lt;code&amp;gt;?&amp;gt;&amp;lt;/code&amp;gt; in your &#039;&#039;config.php&#039;&#039; file. Sometimes text editors add these - for example Notepad on Windows - so you may have to try a different text editor to remove these spaces or blank lines completely.&lt;br /&gt;
&lt;br /&gt;
== Why doesn&#039;t my Moodle site display the time and date correctly? ==&lt;br /&gt;
&lt;br /&gt;
Each language requires a specific language code (called a &#039;&#039;&#039;locale&#039;&#039;&#039; code) to allow dates to be displayed correctly. The language packs contain default standard codes, but sometimes these don&#039;t work on Windows servers.&lt;br /&gt;
&lt;br /&gt;
You can find the correct locale codes for Windows on these two pages: [http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_language_strings.asp Language codes] and [http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_country_strings.asp Country/region] codes (e.g. &amp;quot;esp_esp&amp;quot; for spanish)&lt;br /&gt;
&lt;br /&gt;
These new locale codes can be entered on the Administration &amp;gt;&amp;gt; Configuration &amp;gt;&amp;gt; [[admin/config|Variables]] page, where they override the ones in the currently chosen language pack.&lt;br /&gt;
&lt;br /&gt;
==I receive this error &amp;quot;500:Internal Server Error&amp;quot;==&lt;br /&gt;
You&#039;ll get this error message if there is a syntax error in your .htaccess or httpd.conf files. You will also see this error if your server does not support .htaccess files, especially if it is running PHPsuexec. Also, you may have a directive in your .htaccess or httpd.conf files which are not compatible with your web server version.&lt;br /&gt;
&lt;br /&gt;
==How do I uninstall Moodle?==&lt;br /&gt;
&#039;&#039;&#039;Moodle package installation&#039;&#039;&#039;: If you have downloaded a Moodle package, simply uninstall using your system commands. On Windows PCs, you should access the Control Panel -&amp;gt; Add/Remove Programs. Select the package name and click Change or Remove Programs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Webhost/manual installation&#039;&#039;&#039;: If you have installed Moodle manually or have installed onto a webhost, follow these steps:&lt;br /&gt;
*Delete the moodle database using this mysql command (or delete using your mysql client, e.g. PHPMyAdmin):&lt;br /&gt;
&amp;lt;pre&amp;gt;sql&amp;gt;DROP DATABASE moodle;&amp;lt;/pre&amp;gt;&lt;br /&gt;
:In the above example replace &#039;moodle&#039; with the name of the moodle database you created when installing.&lt;br /&gt;
*Delete the moodledata directory. If you, or your users, have uploaded materials into this directory take a copy of these before deleting this directory.&lt;br /&gt;
*Delete the moodle directory itself. This will delete all of the moodle PHP script files.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==How do I upgrade Moodle? Do I just overwrite the files?==&lt;br /&gt;
Do not overwrite files, it may cause strange errors. You should read the [[Upgrade]] documentation before proceeding.&lt;br /&gt;
&lt;br /&gt;
==Migrating Moodle to a new site or server==&lt;br /&gt;
Migrating Moodle means that you have to move the current installation to a new server, and so may have to change IP addresses or DNS entries. To do this you will need to change the $CFG-&amp;gt;wwwroot value in the config.php on the new server. You will also have to change any absolute links stored in the database backup file (before restoring the file on the new server) either using the admin/replace.php script, your text editor or another &amp;quot;search and replace&amp;quot; tool, e.g. sed. For more details see the [[Moodle_migration | Moodle Migration]] page.&lt;br /&gt;
&lt;br /&gt;
==Fatal error allowed memory size exhausted. How do I increase my php memory limit?==&lt;br /&gt;
You will sometimes see an error message something like this:&lt;br /&gt;
 Fatal error: Allowed memory size of 67108864 bytes exhausted &lt;br /&gt;
 (tried to allocate xx bytes) in /var/www/moodle/yyyy.php&lt;br /&gt;
This error means that the php memory_limit value is not enough for the php script. The memory_limit value is the &amp;quot;allowed memory size&amp;quot; - 64M in the example above (67108864 bytes / 1024 = 65536 KB. 65536 KB / 1024 = 64 MB). You will need to increase the php memory_limit value until this message is not shown anymore. There are two methods of doing this.&lt;br /&gt;
*On a hosted installation, add the following line to your .htaccess file (or create one in the moodle directory if it does not already exist):&lt;br /&gt;
 php_value memory_limit &amp;lt;value&amp;gt;M&lt;br /&gt;
 Example: php_value memory_limit 40M&lt;br /&gt;
*If you have your own server with shell access, edit your php.ini file (make sure it&#039;s the correct one by checking in your phpinfo output) as follows:&lt;br /&gt;
 memory_limit &amp;lt;value&amp;gt;M&lt;br /&gt;
 Example: memory_limit 40M&lt;br /&gt;
Remember that you need to restart your web server to make changes to php.ini effective. An alternative is to disable the memory_limit by using the command &#039;&#039;memory_limit 0&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
==Why does my new installation display correctly on the server, but when I view it from a different machine, styles and images are missing?==&lt;br /&gt;
In the installation instructions, one of the suggested settings for &#039;webroot&#039; is &#039;localhost&#039;. This is fine if all you want to do is some local testing of your new Moodle installation. If, however, you want to view your new installation from another machine on the same local area network, or view your site on the internet, you will have to change this setting:&lt;br /&gt;
*For local testing, &#039;localhost&#039; is fine for the webroot. &lt;br /&gt;
*If you want to test your site from other machines on the same local area network (LAN), then you will have to use the private ip address of the serving machine, (e.g. 192.168.1.2/moodle) or the network name of the serving computer (e.g. network_name_of_serving_machine/moodle) as the web root. Depening on your LAN setup, it may be better to use the network name of the computer rather than its (private) ip address, because the ip address can and will change from time to time. If you don&#039;t want to use the network name, then you will have to speak to your network administrator and have them assign a permanent ip address to the serving machine.&lt;br /&gt;
*Finally, if you want to test your new installation across the internet, you will have to use either a domain name or a permanent (public) ip address/moodle as your web root.&lt;br /&gt;
&lt;br /&gt;
[[Category:FAQ]]&lt;br /&gt;
[[Category:Installation]]&lt;br /&gt;
&lt;br /&gt;
[[es:FAQ Instalación]]&lt;br /&gt;
[[fr:FAQ d&#039;installation]]&lt;br /&gt;
[[nl:Installatie FAQ]]&lt;br /&gt;
[[ja:インストールFAQ]]&lt;br /&gt;
[[ru:Установка FAQ]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Complete_install_packages&amp;diff=25468</id>
		<title>Complete install packages</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Complete_install_packages&amp;diff=25468"/>
		<updated>2007-07-30T19:33:03Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* Start the Moodle installation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Complete install packages are available from [http://download.moodle.org/ Moodle Downloads], located on a tab for each of the operating systems.  The packages are designed for new installations on a server or standalone computer. Please note the standard distributions only contain the Moodle code.&lt;br /&gt;
&lt;br /&gt;
This document provides instructions for using the Windows packages. Separate instructions are available for [[Complete Install Packages for Mac OS X|Mac OS X packages]].&lt;br /&gt;
&lt;br /&gt;
For installation on a Windows 2000 or Windows 2003 server it is good practice to perform a manual install (see the manual installation section in [[Windows_installation|Windows Installation]]). &lt;br /&gt;
&lt;br /&gt;
After installing the Windows package, note that there are other downloads (e.g. additional modules and plugins) that may involve more customization of configuration files.&lt;br /&gt;
&lt;br /&gt;
The complete install packages allow Moodle to be installed, along with the prerequisites that includes a web server, database and scripting language (Apache, MySQL and PHP in this case). Several versions of the complete install package are available. The instructions on the download page provide guidance on which version is likely to be most suitable.&lt;br /&gt;
&lt;br /&gt;
Note: The latest complete install package version components, may not be backwardly compatible. Always check version compatibility of each component if you intend to develop materials on a later version of Moodle than the version installed on your &amp;quot;main&amp;quot; Moodle site.  In short, complete install packages are designed for first time install on a &amp;quot;clean&amp;quot; machine.   &lt;br /&gt;
&lt;br /&gt;
==System requirements==&lt;br /&gt;
  + 256 MB RAM (minimum), 512 MB RAM (recommended)&lt;br /&gt;
  + 160 MB free Fixed Disk (more space will be needed depending on user uploads)&lt;br /&gt;
  + Windows 98/ME (minimum)&lt;br /&gt;
  + Windows NT/2000/XP (recommended)&lt;br /&gt;
&lt;br /&gt;
==Install complete package ==&lt;br /&gt;
===First install Apache, MySQL, PHP===&lt;br /&gt;
Step 1:  [http://download.moodle.org/ Download] the packed-zip file from Moodle.&lt;br /&gt;
 &lt;br /&gt;
Step 2: Unpack the file you downloaded to a drive or partition of your choice and let the default create C:\moodle or W:\moodle or something like this. It is a good practice at this point to rename the C:\moodle to something like C:\Web or C:\Xampplite.  There will be a folder under this called \moodle. &lt;br /&gt;
&lt;br /&gt;
Step 3: Start the &amp;quot;setup_xampp.bat&amp;quot; in the top folder.  This will configure Xammplite. Note: XAMPP makes no entries in the windows registry and no settings for the system variables. &lt;br /&gt;
&lt;br /&gt;
Step 4: Now you are ready to start your webserver.  Use the Xampp_start file.   Once the Xampp_start is open, don&#039;t close it, use Xampp_stop for that purpose.  Xampp program(s) control both Apache and MySQL.  Alternatively you can individually start and stop Apache and MySQL with the bat files found in the top folder such as C:\xampplite .&lt;br /&gt;
&lt;br /&gt;
Step 5: Start your browser and type &amp;lt;nowiki&amp;gt; http://127.0.0.1 or http://localhost &amp;lt;/nowiki&amp;gt;in the address bar. You will either start your first time Moodle installation or if it is already install enter your homepage.&lt;br /&gt;
&lt;br /&gt;
===Start the Moodle installation===&lt;br /&gt;
&lt;br /&gt;
*In your web browser, type the path to the folder containing the Moodle files in te address bar – in this example it’s &amp;lt;nowiki&amp;gt;http://localhost/moodle, in the above example it would be http://localhost&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*The initial install page is displayed.&lt;br /&gt;
&lt;br /&gt;
[[image:Xampp24.gif|thumb|center|600px]]&lt;br /&gt;
&lt;br /&gt;
*Choose your preferred language (English is used in this example) and click the “Next” button.&lt;br /&gt;
&lt;br /&gt;
*A diagnostic report is displayed – hopefully it will look like this, if not you may need to address some issues.&lt;br /&gt;
&lt;br /&gt;
[[image:Xampp25.gif|thumb|center|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Click the “Next” button to continue.&lt;br /&gt;
&lt;br /&gt;
*The paths for your Moodle installation are shown – accept the ones that are shown on your screen.&lt;br /&gt;
&lt;br /&gt;
[[image:Xampp26.gif|thumb|center|400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Click the “Next” button to continue.&lt;br /&gt;
&lt;br /&gt;
*What you enter in the &amp;quot;Host Server&amp;quot; field depends on what you intend to use the new Moodle installation for. &lt;br /&gt;
If you are just going to use it for local testing, then use &#039;localhost&#039;. &lt;br /&gt;
If you are going to test the new installation on a LAN, and will be accessing it from other machines on that LAN, then put the private IP address or network name of the serving machine, followed by a forward slash and moodle: Host Server - 192.168.1.1/moodle&lt;br /&gt;
If you are going to test the installation on the internet, then you will need to put the public ip address followed by a forward slash and moodle: your_ip_address/moodle or you can put your domain name here instead.&lt;br /&gt;
&lt;br /&gt;
*In the next fields, we enter the database settings. The fields are populated with some suggested values.&lt;br /&gt;
&lt;br /&gt;
*We strongly recommend you place a user name and password in this screen. (Don&#039;t forget them).&lt;br /&gt;
&lt;br /&gt;
*DO NOT USE THE “ROOT” USER WITHOUT A PASSWORD FOR PRODUCTION INSTALLATIONS AS THIS CREATES A SECURITY VULNERABILITY&lt;br /&gt;
[[image:Xampp27.gif|thumb|center|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*When the fields have been populated, click the “Next” button to continue.&lt;br /&gt;
&lt;br /&gt;
*Provided the Moodle folder is writable, a message confirming the configuration has been completed will be displayed.&lt;br /&gt;
&lt;br /&gt;
[[image:Xampp29.gif|thumb|center|400px]]&lt;br /&gt;
&lt;br /&gt;
*Click the “ Continue” button to proceed.&lt;br /&gt;
&lt;br /&gt;
The Moodle copyright / licence notices are displayed.&lt;br /&gt;
&lt;br /&gt;
[[image:Xampp30.gif|thumb|center|400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Click the “Yes” button to continue.  In most cases this will be followed by a series of screens that have a continue button on the bottom.  In Moodle 1.8 look for the &amp;quot;Unattended&amp;quot; checkoff box.  This will press the continue button at the bottom of the screen for you. This process stops with Admin user profile settings which needs to be filled out, then goes to the site setting page.&lt;br /&gt;
&lt;br /&gt;
===Congratulations===&lt;br /&gt;
This finishes the installation of a complete package.   Type http://localhost in your browser and Moodle will open. &lt;br /&gt;
&lt;br /&gt;
Your next task will be to configure Moodle.   See [[Administrator_documentation#Configuration]] or [[Administrator_documentation]].  Don&#039;t worry, it is easy to change any of the settings once Moodle is running.&lt;br /&gt;
&lt;br /&gt;
== Installing Apache and MySQL as services==&lt;br /&gt;
(This is only for NT4 | Windows 2000 | Windows XP operating systems)&lt;br /&gt;
&lt;br /&gt;
\xampplite\apache\apache_installservice.bat =&lt;br /&gt;
==&amp;gt; Install Apache 2 as service   &lt;br /&gt;
&lt;br /&gt;
\xampplite\apache\apache_uninstallservice.bat =&lt;br /&gt;
==&amp;gt; Uninstall Apache 2 as service   &lt;br /&gt;
&lt;br /&gt;
\xampplite\mysql\mysql_installservice.bat =&lt;br /&gt;
==&amp;gt; Install MySQL as service   &lt;br /&gt;
&lt;br /&gt;
\xampplite\mysql\mysql_uninstallservice.bat =&lt;br /&gt;
==&amp;gt; Uninstall MySQL as service   &lt;br /&gt;
&lt;br /&gt;
==&amp;gt; After all Service (un)installations, please restart your system!&lt;br /&gt;
&lt;br /&gt;
== Security matters (A MUST READ!)==&lt;br /&gt;
&lt;br /&gt;
As mentioned before, XAMPP is not meant for production use but only for developers &lt;br /&gt;
in a development environment. The way XAMPP is configured is to be open as possible &lt;br /&gt;
and allowing the developer anything he/she wants. For development environments this &lt;br /&gt;
is great but in a production environment it could be fatal. Here a list of missing security &lt;br /&gt;
in XAMPP:&lt;br /&gt;
&lt;br /&gt;
The MySQL administrator (root) has no password.&lt;br /&gt;
The MySQL daemon is accessible via network.&lt;br /&gt;
phpMyAdmin is accessible via network.&lt;br /&gt;
Examples are accessible via network.&lt;br /&gt;
&lt;br /&gt;
To fix most of the security weaknesses simply call the following URL:&lt;br /&gt;
&lt;br /&gt;
http://localhost/security/&lt;br /&gt;
&lt;br /&gt;
The root password for MySQL + phpMyAdmin and also a XAMPP directory protection can be established here.&lt;br /&gt;
&lt;br /&gt;
==Apache Notes==&lt;br /&gt;
&lt;br /&gt;
You should use the apache_start and apache_stop bat files to start and stop apache from running.&lt;br /&gt;
&lt;br /&gt;
==MySQL notes==&lt;br /&gt;
&lt;br /&gt;
(1) The MySQL server can be started by double-clicking (executing)&lt;br /&gt;
    mysql_start.bat. This file can be found in the same folder you installed&lt;br /&gt;
    xampp in, most likely this will be C:\xampplite\.&lt;br /&gt;
    The exact path to this file is X:\xampplite\mysql_start.bat, where&lt;br /&gt;
    &amp;quot;X&amp;quot; indicates the letter of the drive you unpacked xampp into.&lt;br /&gt;
    This batch file starts the MySQL server in console mode. The first &lt;br /&gt;
    intialization might take a few minutes.&lt;br /&gt;
    &lt;br /&gt;
    Do not close the DOS window or you&#039;ll crash the server!&lt;br /&gt;
    To stop the server, please use mysql_shutdown.bat, which is located in the same&lt;br /&gt;
    directory.&lt;br /&gt;
&lt;br /&gt;
(2) To use the MySQL Daemon with &amp;quot;innodb&amp;quot; for better performance, &lt;br /&gt;
    please edit the &amp;quot;my&amp;quot; (or &amp;quot;my.cnf&amp;quot;) file in the /xampplite/mysql/bin &lt;br /&gt;
    directory or for services the c:\my.cnf for windows NT/2000/XP. &lt;br /&gt;
    In there, activate the &amp;quot;innodb_data_file_path=ibdata1:30M&amp;quot;&lt;br /&gt;
    statement. Attention, &amp;quot;innodb&amp;quot; is not recommended for 95/98/ME.&lt;br /&gt;
    &lt;br /&gt;
    To use MySQL as Service for NT/2000/XP, simply copy the &amp;quot;my&amp;quot; &lt;br /&gt;
    / &amp;quot;my.cnf&amp;quot; file to C:\my, or C:\my.cnf. Please note that this &lt;br /&gt;
    file has to be placed in C:\ (root), other locations are not permitted. Then&lt;br /&gt;
    execute the &amp;quot;mysql_installservice.bat&amp;quot; in the mysql folder. 	&lt;br /&gt;
     	&lt;br /&gt;
&lt;br /&gt;
(3) MySQL starts with standard values for the user id and the password. The preset&lt;br /&gt;
    user id is &amp;quot;root&amp;quot;, the password is &amp;quot;&amp;quot; (= no password). To access MySQL via PHP&lt;br /&gt;
    with the preset values, you&#039;ll have to use the following syntax:&lt;br /&gt;
    mysql_connect(&amp;quot;localhost&amp;quot;,&amp;quot;root&amp;quot;,&amp;quot;&amp;quot;);&lt;br /&gt;
    If you want to set a password for MySQL access, please use of mysqladmin.&lt;br /&gt;
    To set the passwort &amp;quot;secret&amp;quot; for the user &amp;quot;root&amp;quot;, type the following:&lt;br /&gt;
    \xampplite\mysql\bin\mysqladmin -u root password secret&lt;br /&gt;
    &lt;br /&gt;
    After changing the password you&#039;ll have to reconfigure phpMyAdmin to use the&lt;br /&gt;
    new password, otherwise it won&#039;t be able to access the databases. To do that,&lt;br /&gt;
    open the file config.inc.php in \xampplite\phpmyadmin\ and edit the&lt;br /&gt;
    following lines:    &lt;br /&gt;
    &lt;br /&gt;
    $cfg[&#039;Servers&#039;][$i][&#039;user&#039;]            = &#039;root&#039;;   // MySQL user&lt;br /&gt;
    $cfg[&#039;Servers&#039;][$i][&#039;auth_type&#039;]       = &#039;http&#039;;   // HTTP authentificate&lt;br /&gt;
&lt;br /&gt;
    So first the &#039;root&#039; password is queried by the MySQL server, before phpMyAdmin &lt;br /&gt;
    may access.&lt;br /&gt;
  	    	&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
Have a lot of fun! Viel Spaß! Bonne Chance!&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Administrator_documentation]] for links that help configure Moodle.&lt;br /&gt;
*[[Installation guide - Moodle for Windows on a USB Memory Stick]]&lt;br /&gt;
*Return to [[Windows installation]]&lt;br /&gt;
*[https://docs.moodle.org/en/Windows_installation_using_XAMPP#Troubleshooting Troubleshooting]if you are running Skype. &lt;br /&gt;
*[[Installing_AMP]] lots of XAMPP stuff.  XAMPP stands for XP, Apache, MySQL,PHP and Perl.  XAMPPlite does not include Perl. MAMP stands for Mac, Apache, MySQL and PHP.  &lt;br /&gt;
*[[Complete Install Packages for Mac OS X]] &lt;br /&gt;
&lt;br /&gt;
[[es:Paquetes_para_Instalaci%C3%B3n_Completa]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Installation]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Installing_AMP&amp;diff=5578</id>
		<title>Installing AMP</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Installing_AMP&amp;diff=5578"/>
		<updated>2006-02-17T23:33:48Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* Windows */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Moodle is written in a scripting language called PHP and stores most of its data in a database. The recommendrd database is MySQL. Before installing Moodle you must have a working PHP installation and a working database to turn your computer into a functional web server platform. These packages can be tricky to set up for average computer users, so this page has been written to try to make this process as simple as possible for different platforms:&lt;br /&gt;
&lt;br /&gt;
== Hosting Service ==&lt;br /&gt;
&lt;br /&gt;
Unfortunately hosting services vary quite a lot in the way they work. Some will even install Moodle for you.&lt;br /&gt;
&lt;br /&gt;
Most will offer a web-based control panel to control your site, create databases and set up cron. Some may also offer terminal access via ssh, so that you can use the command shell to do things.&lt;br /&gt;
&lt;br /&gt;
You should work your way through the [[Installing Moodle|Installation guide]] and take each step at a time. Ask your hosting provider if you get stuck.&lt;br /&gt;
&lt;br /&gt;
== Mac OS X ==&lt;br /&gt;
&lt;br /&gt;
The easiest way to do this is use the Apache server that Apple provides, and add PHP and MySQL using Marc Liyanage&#039;s packages. Both of the pages below come with good instructions that we won&#039;t duplicate here:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PHP&#039;&#039;&#039;: Download from here: http://www.entropy.ch/software/macosx/php/&lt;br /&gt;
* &#039;&#039;&#039;MySQL&#039;&#039;&#039;: Download here: http://www.entropy.ch/software/macosx/mysql/&lt;br /&gt;
&lt;br /&gt;
Once these are installed the standard [[Installing Moodle|Installation guide]] should be fairly straightforward.&lt;br /&gt;
&lt;br /&gt;
== Red Hat Linux ==&lt;br /&gt;
&lt;br /&gt;
You should install all available RPM packages for Apache, PHP and MySQL. One package that people frequently forget is the php-mysql package which is necessary for PHP to talk to MySQL.&lt;br /&gt;
&lt;br /&gt;
Once these are installed the standard [[Installing Moodle|Installation guide]] should be fairly straightforward.&lt;br /&gt;
&lt;br /&gt;
A more detailed walkthrough is here: [[RedHat Linux installation]]&lt;br /&gt;
&lt;br /&gt;
== Windows ==&lt;br /&gt;
&lt;br /&gt;
The easiest way to do this is use one of the complete install packages available from the Downloads page at Moodle.org. [http://download.moodle.org/?lang=en]&lt;br /&gt;
&lt;br /&gt;
Alternatively, use a package like EasyPHP that bundles all the software you need into a single Windows application.  Note that the EasyPHP 1.7 uses the following somewhat older versions:&lt;br /&gt;
&lt;br /&gt;
# apache 1.3.27 (currnet relases is 2.2.0)&lt;br /&gt;
# php 4.3.3 (current stable release is 5.1.3)&lt;br /&gt;
# mysql 4.0.15 (current release is 5.0.18)&lt;br /&gt;
# phpmyadmin 2.5.3&lt;br /&gt;
&lt;br /&gt;
It should be noted that these are not the current releases.  Also many menus for EasyPHP are still in French.  Here are the steps from start to finish for this approach, XAMPP or Windows 2003 with IIS: [[Windows installation]].&lt;br /&gt;
&lt;br /&gt;
==Testing PHP==&lt;br /&gt;
Once you have installed your web server and PHP you should be able to create a file (for example phpinfo.php in the document root) with the following in it:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;?phpinfo()?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should be able to open this file in a web browser by going to to the URL &#039;&#039;&#039;localhost/phpinfo&#039;&#039;&#039; and see a web page that has PHP status information in it such as [[phpinfo|this]].&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Installing Moodle]]&lt;br /&gt;
*[[Installation FAQ]]&lt;br /&gt;
*[[Upgrading Moodle]]&lt;br /&gt;
*[[Debian GNU/Linux installation]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Core]]&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Installation]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/test/index.php?title=Installing_AMP&amp;diff=5576</id>
		<title>Installing AMP</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/test/index.php?title=Installing_AMP&amp;diff=5576"/>
		<updated>2006-02-17T23:31:30Z</updated>

		<summary type="html">&lt;p&gt;Matm: /* Windows */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Moodle is written in a scripting language called PHP and stores most of its data in a database. The recommendrd database is MySQL. Before installing Moodle you must have a working PHP installation and a working database to turn your computer into a functional web server platform. These packages can be tricky to set up for average computer users, so this page has been written to try to make this process as simple as possible for different platforms:&lt;br /&gt;
&lt;br /&gt;
== Hosting Service ==&lt;br /&gt;
&lt;br /&gt;
Unfortunately hosting services vary quite a lot in the way they work. Some will even install Moodle for you.&lt;br /&gt;
&lt;br /&gt;
Most will offer a web-based control panel to control your site, create databases and set up cron. Some may also offer terminal access via ssh, so that you can use the command shell to do things.&lt;br /&gt;
&lt;br /&gt;
You should work your way through the [[Installing Moodle|Installation guide]] and take each step at a time. Ask your hosting provider if you get stuck.&lt;br /&gt;
&lt;br /&gt;
== Mac OS X ==&lt;br /&gt;
&lt;br /&gt;
The easiest way to do this is use the Apache server that Apple provides, and add PHP and MySQL using Marc Liyanage&#039;s packages. Both of the pages below come with good instructions that we won&#039;t duplicate here:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;PHP&#039;&#039;&#039;: Download from here: http://www.entropy.ch/software/macosx/php/&lt;br /&gt;
* &#039;&#039;&#039;MySQL&#039;&#039;&#039;: Download here: http://www.entropy.ch/software/macosx/mysql/&lt;br /&gt;
&lt;br /&gt;
Once these are installed the standard [[Installing Moodle|Installation guide]] should be fairly straightforward.&lt;br /&gt;
&lt;br /&gt;
== Red Hat Linux ==&lt;br /&gt;
&lt;br /&gt;
You should install all available RPM packages for Apache, PHP and MySQL. One package that people frequently forget is the php-mysql package which is necessary for PHP to talk to MySQL.&lt;br /&gt;
&lt;br /&gt;
Once these are installed the standard [[Installing Moodle|Installation guide]] should be fairly straightforward.&lt;br /&gt;
&lt;br /&gt;
A more detailed walkthrough is here: [[RedHat Linux installation]]&lt;br /&gt;
&lt;br /&gt;
== Windows ==&lt;br /&gt;
&lt;br /&gt;
The easiest way to do this is use one of the complete install packages available from the Downloads page at Moodle.org. [http://download.moodle.org/?lang=en]&lt;br /&gt;
&lt;br /&gt;
Alternatively, use a package like EasyPHP that bundles all the software you need into a single Windows application.  Note that the EasyPHP 1.7 uses the following somewhat older versions:&lt;br /&gt;
&lt;br /&gt;
# apache 1.3.27 (currnet relases is 2.2.0)&lt;br /&gt;
# php 4.3.3 (current stable release is 5.1.3)&lt;br /&gt;
# mysql 4.0.15 (current release is 5.0.18)&lt;br /&gt;
# phpmyadmin 2.5.3&lt;br /&gt;
&lt;br /&gt;
It should be noted that these are not the current releases.  Also many menus for EasyPHP are still in French.  Here are the steps from start to finish for this approach or XAMPP: [[Windows installation]].&lt;br /&gt;
&lt;br /&gt;
==Testing PHP==&lt;br /&gt;
Once you have installed your web server and PHP you should be able to create a file (for example phpinfo.php in the document root) with the following in it:&lt;br /&gt;
&lt;br /&gt;
   &amp;lt;?phpinfo()?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should be able to open this file in a web browser by going to to the URL &#039;&#039;&#039;localhost/phpinfo&#039;&#039;&#039; and see a web page that has PHP status information in it such as [[phpinfo|this]].&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Installing Moodle]]&lt;br /&gt;
*[[Installation FAQ]]&lt;br /&gt;
*[[Upgrading Moodle]]&lt;br /&gt;
*[[Debian GNU/Linux installation]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Core]]&lt;br /&gt;
[[Category:Administrator]]&lt;br /&gt;
[[Category:Installation]]&lt;/div&gt;</summary>
		<author><name>Matm</name></author>
	</entry>
</feed>