Jump to content

New module type: WireMail


ryan

Recommended Posts

Exactly. How you log things is up to you, but for debugging purposes it's totally valid to edit core files. Just revert back to original state after you've found your issue.

Thanks. I feel silly now: I should have consulted my Postfix logs.

I did:

journalctl --since "20 min ago"

I noticed: status=bounced (SMTPUTF8 is required, but was not offered by host..

So I did a web search and ran this config command:

postconf -e smtputf8_enable=no

Now the mail is sent! :lol:

I had already tested the dumping inside WireMail.php.. I'll leave info about it below for future generations.

if($toName) $to = $this->bundleEmailAndName($to, $toName); // bundle to "User Name <user@example.com"
die(var_dump($to, $this->subject, $body, $header, $param));
if(@mail($to, $this->subject, $body, $header, $param)) $numSent++;

Header was like this:

From: user@mysite.com X-Mailer: ProcessWire/WireMail Content-Type: text/plain; charset="utf-8"

  • Like 3
Link to comment
Share on other sites

  • 2 months later...
  • 4 months later...
  • 5 months later...

I've had problems sending HTML email.
It appears some php configurations don't like \r\n (*nix). This has come up on more than one occasion on dedicated hosting environments.

I've had to modify WireMail.php to send HTML email correctly.

		 if($this->bodyHTML) {
			if(!strlen($text)) $text = strip_tags($html); 
			$boundary = "==Multipart_Boundary_x" . md5(time()) . "x";
			$header .= PHP_EOL."MIME-Version: 1.0";
			$header .= PHP_EOL."Content-Type: multipart/alternative; ".PHP_EOL." boundary=\"$boundary\"";
			$body = "This is a multi-part message in MIME format." .PHP_EOL.PHP_EOL. 
				"--$boundary" . PHP_EOL . 
				"Content-Type: text/plain; charset=\"utf-8\"" .PHP_EOL . 
				"Content-Transfer-Encoding: 7bit" .PHP_EOL.PHP_EOL. 
				"$text" .PHP_EOL.PHP_EOL. 
				"--$boundary". PHP_EOL . 
				"Content-Type: text/html; charset=\"utf-8\"".PHP_EOL . 
				"Content-Transfer-Encoding: 7bit".PHP_EOL.PHP_EOL . 
				"$html" .PHP_EOL.PHP_EOL . 
				"--$boundary--". PHP_EOL;
		} else {
			$header .= PHP_EOL."Content-Type: text/plain; charset=\"utf-8\""; 
			$body = $text; 
		}
Link to comment
Share on other sites

  • 2 months later...
On 4/21/2017 at 6:15 PM, horst said:

@Mackski: please refer to the RFCs for email!

https://tools.ietf.org/html/rfc2822#section-2.2

I only replaced \r\n with PHP_EOL in the core.

I now have now come across this in two cases, where thunderbird in particular, will not display HTML email, UNLESS I use the above mentioned code.

This goes for 2.7 >
I'm guessing it's a delivery / configuration issues, but why it doesnt work with \r\n I do not know.

Strangley localhost sends correctly, comparing email sources, I can see the production server is adding additional returns:

Local:

X-Mailer: ProcessWire/WireMail
MIME-Version: 1.0
Content-Type: multipart/alternative;
  boundary="==Multipart_Boundary_x971272fd25f1cf0be14fb1604bb269eax"
Message-Id: <20170705010932.9296B41846@localhost.localdomain>
Date: Wed,  5 Jul 2017 11:09:32 +1000 (AEST)

Production:

X-Mailer: ProcessWire/WireMail
MIME-Version: 1.0
Content-Type: multipart/alternative;
 
  boundary="==Multipart_Boundary_xc4dc56a7cc1f6fe4eadc7f63e3e9f458x"
Message-Id: <20170704234256.C3CA113208EC@XXX.XXX.com.au>
  Date: Wed,  5 Jul 2017 09:42:56 +1000 (AEST)

 

Could be more sinister, gmail displays the HTML as:
So it might be the way I'm reading the file?
ie: wireRenderFile('path/to/email/template');

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=

w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">=0A<html xmlns=3D"http://www.=

w3.org/1999/xhtml">=0A<head>=0A<meta name=3D"viewport" content=3D"width=3Dd=

evice-width" />=0A<meta http-equiv=3D"Content-Type" content=3D"text/html; c=

harset=3DUTF-8" />=0A<style>=0A/* -------------------------------------=0A =

   GLOBAL=0A------------------------------------- */=0A* {=0A  margin: 0;=

=0A  padding: 0;=0A  font-family: "Helvetica Neue", "Helvetica", Helvetica,=

 

Link to comment
Share on other sites

On 5.7.2017 at 3:08 AM, Mackski said:

I only replaced \r\n with PHP_EOL in the core.

Simply do not blindly do that. PHP_EOL is using the linebreak of the OS your running the code on, whereas things like the email rfc do define a fixed linebreak notation, which can differ from your OS selected one. 

  • Like 1
Link to comment
Share on other sites

5 minutes ago, LostKobrakai said:

Simply do not blindly do that. PHP_EOL is using the linebreak of the OS your running the code on, whereas things like the email rfc do define a fixed linebreak notation, which can differ from your OS selected one. 

While I understand this is not ideal, it's the only way to get things to work with wiremail on the servers in question. Other than sending plain text emails, or using a third party mail library.

Link to comment
Share on other sites

If you host is tampering with emails I'd really suggest you to send mails via an smtp server – could be installed on the same host as well. Trying to fix such issues can easily cause you a lot more trouble as you can see and it's not even garanteed you can fix it from php.

  • Like 3
Link to comment
Share on other sites

Just for the record, we used to see similar issues, and the easiest solution was to convert all instances of \r\n to \n. Can't remember all the details, but this tweak has been in use at least for a year or two now, and so far we haven't encountered any additional issues.

I know that the RFC specifically demands \r\n, but for some reason certain recipient systems seem to mess up HTML emails with that in place. It is my experience that \n works much better, regardless of the standard. And yes, we use a separate SMTP server (which in turn uses another SMTP server).

Obviously it could be something about that setup, but if you google around a bit, \n instead of \r\n is a surprisingly commonly used solution :)

  • Like 4
Link to comment
Share on other sites

I'm trying this basic example on my localhost:

$mail = wireMail();
$numSent = $mail->to($toEmail)->subject($subject)->body($textBody)->send();

Is there a way to tell whether it's working, other than setting the $toEmail to my email address, or is there something I can do to my localhost, since I'm not receiving the email? I'm using FastComet hosting... SSL/TLS settings... to my Gmail... from AMPPS... ??? Any tips?

Link to comment
Share on other sites

  • 2 weeks later...

Hi there what do you mean

"Render inline images in body and signatures (using string replacements for the image urls - prepending the site URL), also floating images are working"

Currently im using wire mail as my email setup and i create an html email with images included but.. whenever i view it in microsoft outlook the image were block.  is there a way to unblock the images in outlook in wiremail setup like the php mailer when using images you have to upload the images within the phpmailer folder?

Thanks for the answer in advance..

Here's the Screenshot in outlook..

sample.png.d53f1ec1fcb14109565dcfaeda383b68.png

 

 

 

Link to comment
Share on other sites

5 hours ago, naldrocks98 said:

Hi there what do you mean

"Render inline images in body and signatures (using string replacements for the image urls - prepending the site URL), also floating images are working"

so if you have your html text in a $body variable, you can then do something like this:

<?php

$base_url 		= 'https://www.example.com';
$absoluteFiles 	= $base_url . '/site/assets/files/';
$alignLeft 		= 'style="float:left;margin-right:10px;"';


$placeholders = array(
	'class="align_left"',
	'/site/assets/files/',
);

$replacements = array(
	$alignLeft,
	$absoluteFiles,
);

$body = str_replace($placeholders, $replacements, $body);

 

  • Like 1
Link to comment
Share on other sites

  • 1 year later...

Hi Ivan,

I think you can try to instantiate two parallel vars by calling the extention class names. At least you should give it a quick testing, if that works. I never have done this.

$smtp = new WireMailSmtp();
$mgun = new WireMailMailGun();

You need to check if those initiated objects need to be passed any config data to work.

 

EDIT: yep, and leave the predefined instance wire('mail') alone.

  • Like 3
Link to comment
Share on other sites

Thanks, @horst. That was about what I was thinking. But my desire was to use predefined WireMail instance as a lot of code already relies on it. As I can guess from your answer there is no way to be sure which of the installed WireMail modules will be used in $mail API variable...

Or is there? I am  asking again thinking about the other use case I am keeping in mind. I am using your wonderful WireMailSmtp for production, but switch to @LostKobrakai's WireMail Testing in dev. So I wish I could have both installed and use one of them for $mail depending on some $env variable. Is there a way to do it?

 

 

Link to comment
Share on other sites

1 minute ago, Ivan Gretsky said:

Here it is, @adrian. Not in the modules directory, unsupported, and does not work without some minor modifications with recent WireMail versions, but serves me well for quite a while. Thanks, @LostKobrakai!

Thanks - now I understand all the rationale here. 

My approach is to simply permanently turn on the Mail Interceptor panel in Tracy - it logs calls to send emails rather than sending them. And when you want to test send to yourself instead of the actual recipients, it can handle that as well.

Just another option if you think it would be ok in your workflow.

  • Like 1
Link to comment
Share on other sites

5 minutes ago, Ivan Gretsky said:

Will this method work everywhere, @adrian ? I mean sending emails from hooks and scripts bootstraping PW initiated via cron? I really can't allow to accidentally send a few letters))

I think it should work everywhere.

I just tested a bootstrapped page:

<?php require './index.php';

$mail = \ProcessWire\wireMail();

$mail->to('test@gmail.com', 'Test User');
$mail->from = 'me@gmail.com'; $mail->subject('Test');
$mail->body('Blah blah');

$numSent = $mail->send();

and Tracy captured it just fine:

image.png.8796f8a58f4e9b64f5269b48e6b1fbd0.png

The one key thing I would do is ensure that Mail Interceptor is enabled in the config settings, rather than via Sticky in the Panel Selector so that it can't be disabled accidentally.

I would also check the "Force Guest users into Development mode on localhost" option so that even if you're not logged in, Tracy will be active and intercepting an emails.

Also, for your own peace of mind, I would suggest checking everything with your email address as the only TO/CC/BCC until you are convinced that Tracy is working as expected.

I find it invaluable when testing all sorts of emails.

  • Like 3
Link to comment
Share on other sites

Additionally to adrians suggestion to use TracyDebugger, there also is a possible solution to programmatically adjust between different installed WireMail extensions.

(Initially I understood your question in a wrong context. I thought you would want to use both directly in production mode. But if you want to use one for debug mode and one for production, you may define / setup something in your config.php and ready.php.)

I would define an extra var in site/config.php that, set to true, enables the wiremailsmtp (production) mode. If it is set to something other or completly missing, enable the wiremail debug extension.

needed code may look like this:

// in site/config.php
$config->useProductionMailclass = false;

// in site/ready.php
$wireMailClassProduction = 'WireMailSmtp';
$wireMailClassDebug = 'WireMailTesting';
$neededWireMailClass = true === $config->$config->useProductionMailclass ? $wireMailClassProduction : $wireMailClassDebug;

// now read which version currently is set to use
if($mail->className != $neededWireMailClass) {
	// the wrong class is in use, change it:
	foreach($modules as $module) {
		$parents = class_parents("$module"); 
		if(in_array('WireMail', $parents) && $modules->isInstalled("$module")) { 
			if($module->className == $neededWireMailClass) {
				$mail = wire('modules')->get("$module"); 
				break;
			}
		}
	}
}
// do a final validation and add an error handling for when the desired module isn't loaded at this step!
if($mail->className != $neededWireMailClass) {
	die('Something weird is gooing on here with WireMail-Classes');
}

 

  • Like 4
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...