Go to main content

Textpattern CMS support forum

You are not logged in. Register | Login | Help

#1273 2012-12-07 14:35:02

Gocom
Developer Emeritus
From: Helsinki, Finland
Registered: 2006-07-14
Posts: 4,533
Website

Re: zem_contact_reborn 4.0.3.20

r4950 introduces ‘mail.handler’ callback event. That even can be used to override the default mail() based sending. If something is attached to the event, the handler(s) are fired instead of the default handler.

Using the event happens similarly to any other callback:

/**
 * Register to 'mail.header' event.
 */

	register_callback('abc_smtp_sender', 'mail.handler');

/**
 * Sets your SMTP server (Gmail) username.
 *
 * Can/should be moved to config.php.
 */

	define('abc_stmp_username', 'yourusername@gmail.com');

/**
 * Sets your SMTP server (Gmail) password.
 *
 * Can/should be moved to config.php.
 */

	define('abc_stmp_password', 'yourpassword');

/**
 * Send emails over SMTP.
 *
 * This function replaces the default mail handler. Basic example
 * that uses PHPMailer for sending emails over Gmail SMTP server.
 *
 * Expects that PHPMailer is installed to 'phpmailer' directory located
 * next to '/textpattern' directory, the same directory where Textpattern
 * was installed to.
 *
 * @param  string $event   The callback event
 * @param  string $step    The callback step
 * @param  array  $data    The raw arguments passed to send_email()
 * @param  string $send_to Encoded receiver
 * @param  string $subject Encoded subject
 * @param  string $body    Encoded body
 * @param  string $headers Encoded headers
 * @return bool   TRUE on success, or FALSE on failure
 */

	function abc_smtp_sender($event, $step, $data, $send_to, $subject, $body, $headers)
	{
		require_once dirname(txpath) . '/phpmailer/class.phpmailer.php';

		extract($data);

		$mail = new PHPMailer();
		$mail->IsSMTP();
		$mail->SMTPAuth = true;
		$mail->SMTPSecure = 'tls';
		$mail->Host = 'smtp.gmail.com';
		$mail->Port = 587;
		$mail->Username = abc_stmp_username;
		$mail->Password = abc_stmp_password;

		$mail->SetFrom($from_address, $from_name);

		if ($reply_address)
		{
			$mail->AddReplyTo($reply_address, $reply_name);
		}

		$mail->Subject = $subject;
		$mail->Body = $body;
		$mail->AddAddress($to_address, $to_name);
		return $mail->Send();
	}

That all is just a basic (untested) example to give the rough idea.

Last edited by Gocom (2012-12-07 14:37:36)

Offline

#1274 2012-12-07 14:56:41

mrdale
Member
From: Walla Walla
Registered: 2004-11-19
Posts: 2,215
Website

Re: zem_contact_reborn 4.0.3.20

So how hard would it be to adapt postmaster to use this function?

Offline

#1275 2012-12-07 19:35:43

ruud
Developer Emeritus
From: a galaxy far far away
Registered: 2006-06-04
Posts: 5,068
Website

Re: zem_contact_reborn 4.0.3.20

Gocom wrote:

If you don’t mind me asking, what bugs specifically? The basis of the send_email() function is the same as txpMail(), and it does same type of encoding. It’s the same function, but with configurable options meant for sending generic email.

No problem. I wrote that from memory, so I didn’t have the details then… so, here we go. Not all are bugs.

1. It only allows one “To” address. Accepting multiple recipient addresses is something ZCR and probably Postmaster would need. Ideally “To_address” accepts an array. If so, then “To_name” should do the same. Same applies to the Reply-To address although fewer people will set multiple addresses there.

2. header values aren’t encoded using encode_mailheader():

foreach ($headers as $field => &$value)
{
$value = strip_rn($field.': '.$value);
}

3. And no check is done on the validity of the field names, although arguably, whoever calls this function should check that.

4. To_name, From_name and Reply_name are optional parameters, in the function call they are at the beginning of the parameter list instead of at the end. If you look at the PHP mail function, i’d order them like this:

 send_email($to_address, $subject, $body, $headers = array(), $from_address = '', $reply_address = '', $to_name= '', $from_name = '', $reply_name = '')

5. If to_name is not set, this code below technically correct, but I’ve seen Spamassassing treat this as spam because it really likes the “to” address in “< >” in all cases, even if no name is supplied. Doing so isn’t required per RFC, but certainly valid. You could get rid of the “else” part and trim the result to get rid of the extra space if to_name is empty. Same could be done for reply-to and from:

if ($to_name)
{
$to_name = encode_mailheader(strip_rn($to_name), 'phrase');
$send_to = $to_name.' <'.$to_address.'>';
}
else
{
$send_to = $to_address;
}

6. In the code above, the strip_rn isn’t applied to to_address. Same applies to reply-to and from.

7. This one is funny. I have/had that in ZCR as well. Why is the condition !IS_WIN instead of IS_WIN?

$sep = !IS_WIN ? "\n" : "\r\n";

8. Allow a different “x-mailer” header by doing this only if it isn’t supplied in the headers:

$headers['X-Mailer'] = 'Textpattern';

9. Can we finally drop the ISO-8859-1 support? TXP does UTF-8 every else. If there were mail clients that didn’t support UTF-8 when TXP was released, surely no-one is using them now anymore. The whole utf_decode stuff is really an ugly hack. Is there anyone who really needs this, raise your hand!

10. Is_valid_email() is not future proof. It limits the TLD to 6 characters. PHP has some built in support for this now. It does treat user@localhost type addresses as valid, but it’s not hard to exclude those with a trivial regex (if you want to exclude them at all)

filter_var($email, FILTER_VALIDATE_EMAIL)

By wrong encoding do you mean multibyte handling (which supposedly is correct as long as Textpattern’s header encoder function works as supposed)?

I sure hope it works as supposed. I wrote that one ;)

As far as I know, the function does strip out any newlines and validates email addresses – both which should prevent actual injections. One thing it doesn’t do is stripping NULL bytes. Do you mean that?

I hadn’t actually thought about that one. ZCR strips NULL bytes in both header and body.

Adding callback functionality is on my to-do list

return callback_event('mail.handler', '', 0, $arguments, $send_to, $subject, $body, $headers) !== '';

11. If people want to use the phpmailer add-on, then it’s perhaps easier to pass on unprocessed parameters. Strip_rn and the newline corrections are fine, but phpmailer encodes headers by itself and expects additional headers as an array. It has it’s on methods for adding from/to/reply-to headers, see class.phpmailer

12. Not sure what $arguments does. Perhaps my PHP/TXP knowledge is getting a bit rusty.

Offline

#1276 2012-12-07 20:07:36

Gocom
Developer Emeritus
From: Helsinki, Finland
Registered: 2006-07-14
Posts: 4,533
Website

Re: zem_contact_reborn 4.0.3.20

ruud wrote:

2. header values aren’t encoded using encode_mailheader()

Which is pretty much intended. Encoding the whole value will limit what the header can contain. I can add that, but well…

3. And no check is done on the validity of the field names, although arguably, whoever calls this function should check that.

Headers can be anything. I for do not want to limit the headers in a way or other. It would same type of nonsense as PHP validating what can be passed to header() (what it actually does but thankfully it’s deprecated as of 5.3).

To_name, From_name and Reply_name are optional parameters, in the function call they are at the beginning of the parameter list instead of at the end. If you look at the PHP mail function, i’d order them like this:

I would really want to keep the related arguments bundled together. If there ever is going to be new arguments added to the function, the positions won’t make much sense.

The arguments in PHP accept any possible combinations allowed, but send_email() requires just addresses. As such having the arguments together makes sense, right? The code reads well and you clearly know which name is which.

5. I’ve seen Spamassassing treat this as spam because it really likes the “to” address in “< >” in all cases

Good to know. Will add.

6. In the code above, the strip_rn isn’t applied to to_address. Same applies to reply-to and from.

The addresses are filtered, which makes it unnecessary. If the filterer allows control characters, then there is a bug.

Allow a different “x-mailer” header by doing this only if it isn’t supplied in the headers

Textpattern is the application that is doing the sending tho.

9. Can we finally drop the ISO-8859-1 support? TXP does UTF-8 every else. If there were mail clients that didn’t support UTF-8 when TXP was released, surely no-one is using them now anymore. The whole utf_decode stuff is really an ugly hack. Is there anyone who really needs this, raise your hand!

Agreed, it’s nasty. Not really a hack, but doesn’t work correctly. Basically destroys the content.

You might think that time has changed, but the webmail clients we use to this day are the same and as bad and limited. We here at work send some thousand emails each month to customers and few percent of those that receive those messages, don’t see those emails properly for reason or other.

But even then, I do agree that the conversion should probably be dropped. And the normal emails Textpattern itself sends will work regardless, being mainly ASCII only, and for more exotic languages, the conversion has never been usable.

Is_valid_email() is not future proof. It limits the TLD to 6 characters. PHP has some built in support for this now.

is_valid_email() and neither PHP’s filter do exactly proper validation. Both flag valid email addresses unfortunately, being simple regex implementations. Replacing the regex with PHP’s filterer is planned, even that it doesn’t make it future or full proof, but works certainly bit better.

I hadn’t actually thought about that one. ZCR strips NULL bytes in both header and body.

NULL bytes nor any other control bytes shouldn’t matter, even that some of the 1024671 PHP classes seem to do that. Nothing else than LF and CR should have relevance in email headers. Plus, Textpattern’s HTTP stack removes NULL bytes already from there at least.

11. If people want to use the phpmailer add-on, then it’s perhaps easier to pass on unprocessed parameters.

The callback functions receive both encoded and raw values. The $arguments contains the initial arguments supplied to send_email() as mentioned in the above example I posted.

Last edited by Gocom (2012-12-07 20:23:59)

Offline

#1277 2012-12-07 21:06:03

ruud
Developer Emeritus
From: a galaxy far far away
Registered: 2006-06-04
Posts: 5,068
Website

Re: zem_contact_reborn 4.0.3.20

Gocom wrote:

Encoding the whole value will limit what the header can contain. I can add that, but well…

True. Hadn’t thought of that. No problem if it’s not encoded, as long as that’s documented.

Headers can be anything. I for do not want to limit the headers in a way or other. It would same type of nonsense as PHP validating what can be passed to header() (what it actually does but thankfully it’s deprecated as of 5.3).

Field names, not values. There are restrictions on field names (printable us-ascii, no spaces or colons). Not important enough to check probably, because these typically aren’t supplied by whoever visits the website.

I would really want to keep the related arguments bundled together. If there ever is going to be new arguments added to the function, the positions won’t make much sense.

The arguments in PHP accept any possible combinations allowed, but send_email() requires just addresses. As such having the arguments together makes sense, right? The code reads well and you clearly know which name is which.

How about having a list of arguments, to call send_mail with an array of parameters, much like how tag handlers work. Easier to extend in the future. (if only PHP supported named parameters).

Textpattern is the application that is doing the sending tho.

Makes sense. Otherwise, I can always switch to using an X-plugin header :)

NULL bytes nor any other control bytes shouldn’t matter, even that some of the 1024671 PHP classes seem to do that. Nothing else than LF and CR should have relevance in email headers.

Actually, they’re not allowed anymore since RFC 2822:
“The NUL character (ASCII value 0) was once allowed, but is no longer for compatibility reasons”
Various security software will reject mails that contain NUL characters (for example: Symantec mail security)

Plus, Textpattern’s HTTP stack removes NULL bytes already from there at least.

Where does that happen? I grepped for x00. Didn’t find it.

The callback functions receive both encoded and raw values. The $arguments contains the initial arguments supplied to send_email() as mentioned in the above example I posted.

Aaah… I missed the part where $arguments was defined. Good.

Last edited by ruud (2012-12-09 14:24:06)

Offline

#1278 2012-12-07 21:20:59

Gocom
Developer Emeritus
From: Helsinki, Finland
Registered: 2006-07-14
Posts: 4,533
Website

Re: zem_contact_reborn 4.0.3.20

ruud wrote:

Where does that happen? I grepped for x00. Didn’t find it.

PHP has “\0” for NULL too. Textpattern runs POST and GET parameters through its own deNull().

How about having a list of arguments, to call send_mail with an array of parameters, much like how tag handlers work. Easier to extend in the future. (if only PHP supported named parameters).

I would rather write a class at that point and use objects. I personally don’t like that array stuff that much to be honest. Makes writing documentation hard and restricted too.

Not important enough to check probably, because these typically aren’t supplied by whoever visits the website.

That’s what I was after.

Actually, they’re not allowed anymore since RFC 2822:

Good to know. Will add the filtering to strip_rn().

Offline

#1279 2012-12-09 14:20:31

ruud
Developer Emeritus
From: a galaxy far far away
Registered: 2006-06-04
Posts: 5,068
Website

Re: zem_contact_reborn 4.0.3.20

Gocom wrote:

ruud wrote:: header values aren’t encoded using encode_mailheader()

Which is pretty much intended. Encoding the whole value will limit what the header can contain. I can add that, but well…

Two arguments for encoding the $header values in send_mail:

1. I would expect the callback event to do it’s own escaping. I know class.phpmailer does. So you need the unencoded header values there.
2. TXP does encoding / escaping as late as possible in most other places.

The only two additional headers I can think of that might be limited – if you encode them completely – are CC and BCC. Perhaps these could be added as function arguments.

I hope To/From/Reply-To/CC/BCC names/addresses can be supplied as array(‘address’ => ‘name’, address2’ => ‘name’). That makes it easy to supply multiple addresses for one header. This is something that can be done now, because it’s a new function, but would be harder to implement once 4.6 is released. Even though this adds CC/BCC, it would reduce the number of arguments:

send_email($from, $to, $subject, $body, $reply = array(), $cc = array(), $bcc = array(), $headers = array())

PS. if no reply-to address is specified, mail clients will automatically reply to the address(es) in the From header. So it doesn’t have to be added.

Offline

#1280 2012-12-11 20:42:30

ruud
Developer Emeritus
From: a galaxy far far away
Registered: 2006-06-04
Posts: 5,068
Website

Re: zem_contact_reborn 4.0.3.20

Yay for r4980

If I’m reading the code correctly, the function arguments $from (and to/cc/bcc/reply-to) can now be in one of the following formats (which makes it very flexible):

'user@example.com'
array('user1@example.com', 'user2@example.com')
array('user1@example.com' => 'name1', 'user2@example.com' => 'name2')

A few small things:

if ($charset == 'UTF-8')
{
  $name = utf8_decode($name);
}

Should probably have != instead of ==.

foreach ($headers as $field => $value)
{
  if (!isset($envelope[$field]) && preg_match('/[A-z0-9-_]/i', $value))
  {
    $envelope[] = $field.': '.encode_mailheader(strip_rn($value), 'phrase');
  }
}

I can’t figure out the purpose of the preg_match there, but A-z should probably be A-Z or a-z.
If it was to ensure a valid header field name, RFC2822 3.6.8 says: /^[\041-\071\073-\176]+$/ (printable US-ASCII characters except SP and colon)
If it was to avoid an adding a header without a value, I’d simply check if the value is a non-empty string.

The values in those headers can contain utf-8 as well, so may need utf-8 decode if charset != UTF8.

Offline

#1281 2012-12-12 00:16:30

Gocom
Developer Emeritus
From: Helsinki, Finland
Registered: 2006-07-14
Posts: 4,533
Website

Re: zem_contact_reborn 4.0.3.20

The regular expression, just like character set conversion were overlooked. Were there for no reason, basically leftovers.

I was supposed to replace the placeholder regular expression with a header field validation, but I suppose I never did.

I’ve now fixed those, so, thank you.

ruud wrote:

If I’m reading the code correctly, the function arguments $from (and to/cc/bcc/reply-to) can now be in one of the following formats (which makes it very flexible):

That would be correct.

Offline

#1282 2013-01-07 15:38:25

hilaryaq
Plugin Author
Registered: 2006-08-20
Posts: 335
Website

Re: zem_contact_reborn 4.0.3.20

Hi All, I’ve edited zem contact reborn to be HTML5 valid, and include two new HTML5 tags of placeholder and autofocus on any field like ‘placeholder=“Please enter your name”’, anyone interested in the edited code? And if so where do I put it, can put the code to copy and paste from my own site if that’s handiest??


…………………
I <3 txp
…………………

Offline

#1283 2013-01-08 06:34:54

jstubbs
Moderator
From: Hong Kong
Registered: 2004-12-13
Posts: 2,395
Website

Re: zem_contact_reborn 4.0.3.20

@hiliaryaq – sounds perfect, I’d like to use your updated plugin, but hopefully Ruud will add it to the new version of ZCR whenever that is?

For adding a jquery date picker to a ZCR input I need an #id to get the calendar attached to the field. Is there a way to add an #id to a text field – can’t see it at the moment.

Last edited by jstubbs (2013-01-08 06:35:45)

Offline

#1284 2013-01-08 14:06:42

uli
Moderator
From: Cologne
Registered: 2006-08-15
Posts: 4,304

Re: zem_contact_reborn 4.0.3.20

jstubbs wrote:

Is there a way to add an #id to a text field – can’t see it at the moment.

Whatever you put into the name attributes is used as the ID.


In bad weather I never leave home without wet_plugout, smd_where_used and adi_form_links

Offline

Board footer

Powered by FluxBB