Jump to content
teppo

Module: WireMailSwiftMailer

Recommended Posts

This module integrates Swift Mailer mailing library to ProcessWire, providing support for three different "transports" or methods of sending email: SMTP, Sendmail and Mail (essentially PHP's native mail() function).

WireMail is email-related base class for ProcessWire. See this post by Ryan for the details. Important thing to note here is that a) it's brand new, so as of this writing you'll need a fresh dev version of ProcessWire to use this and b) it makes integrating new ways of handling email-related tasks very easy.

Getting started

You can download or clone the module from GitHub: https://github.com/teppokoivula/WireMailSwiftMailer/.

Using this module is as simple as downloading / cloning it to your modules directory and installing it. If you're going to use SMTP or Sendmail features, insert correct SMTP credentials / Sendmail command to module settings first.

Third transport, Mail, is included simply because it's a native feature of Swift Mailer; if you're going to use it, I would suggest against installing this module. ProcessWire's native WireMail implementation handles this part just fine.

Basic usage

Sending emails should be done using wireMail() function -- if you use mail() directly, you're going to bypass ProcessWire's email handling features entirely. Main difference between mail() and wireMail() is the order and number of arguments:

$number_of_recipients = wireMail($to, $from, $subject, $body);

For more information please take a look at README.

This module is released under GPLv2 (just like ProcessWire itself) with the exception of included Swift Mailer library, which is copyright © Fabien Potencier and released under the MIT license.

  • Like 20

Share this post


Link to post
Share on other sites

This is fantastic teppo!

I don't necessarily think you should (as it may make the module unnecessarily complex), but do you have any plans to implement any of the SwiftMailer plugins like Decorator, AntiFlood, and Throttler? I use these for sending out bulk emails to subscribers.

I think perhaps in these cases it is simpler if we just include swiftmailer separately in the appropriate template/module code, but thought I'd raise it in case you have any ideas along these lines.

  • Like 1

Share this post


Link to post
Share on other sites

@adrian: I browsed through the plugins just today, wondering if (and how) some of those should be implemented. Not sure yet, but there's undeniably a lot of useful stuff there and it'd be shame not to put any of those in use.

One could always use wireMail() to return instance of WireMailSwiftMailer and it could, in turn, return instance of SwiftMailer.. though admittedly that's not so different from instantiating it yourself :)

  • Like 1

Share this post


Link to post
Share on other sites

Thanks Teppo, this is great! I'm looking forward to using this one. I did try to install but ran into some troubles. I was unable to get it to save SMTPServer or SMTPPort. I tracked that down to an issue with field dependencies (in the core, not your module). I've now fixed that in the core, but you may want to remove the requiredIf condition from those two fields if possible, at least temporarily, as I need to do more testing with the core changes I made before committing to GitHub. 

Once I was able to save the SMTPServer and SMTPPort settings, I tried to use the module but keep getting this message:

Fatal error: Class 'Swift_Message' not found in /Volumes/RyMain/Users/ryan/htdocs/cpi/site/modules/WireMailSwiftMailer/WireMailSwiftMailer.module on line 261

It looks like this condition is failing somehow: 

if ($this->transport != "Smtp" || $this->SMTPServer && $this->SMTPPort && $this->senderAddress) 

If I remove that line above (as well as the closing brace further in the function) then I no longer get errors. 

Following that, I configured it for Gmail per the instructions you linked to. The instructions said to choose "SSL/TLS". I chose "TLS" first, but that didn't work. So next I tried "SSL", and that worked. So SMTP setup is now working for me and it seems to work great.

Some other things to mention:

1. The module should not be autoload, if possible. WireMail is intended to be loaded on demand rather than on every request. 

2. The module should not be singular, if possible. When someone makes a call to wireMail(), we want to make sure we're returning them a brand new copy rather than one that might already have some email settings populated in it. That's why singular should be false, so that every time the module is retrieved a new instance is born.

3. The module version number shouldn't have preceding zeros, as this starts PHP thinking it's an octal number or something else (I don't recall). So version number should be 6 rather than 006. 

4. The require() statement in your init() function should likely be a require_once(), and it should ideally include the full path, just in case another copy of of the same directory name exists elsewhere in the PHP path. i.e. 

require_once(dirname(__FILE__) . '/Swift-' . self::SWIFT_VERSION . '/lib/swift_required.php'); 
  • Like 3

Share this post


Link to post
Share on other sites

@ryan: thanks, great suggestions!
 
I did notice the issue with saving settings, but had planned to reduce it to a proper test case and submit as an issue. Should've acted faster and disabled it right away, though, to avoid any unnecessary confusion  :)

Autoload and singular state were carried over from the original module, the intention of which was quite different from current implementation. I've taken care of these already, but will have to change the require logic you mentioned, as that admittedly no longer makes sense (and path part would've made sense even in the original form).

Once I was able to save the SMTPServer and SMTPPort settings, I tried to use the module but keep getting this message:

Fatal error: Class 'Swift_Message' not found in /Volumes/RyMain/Users/ryan/htdocs/cpi/site/modules/WireMailSwiftMailer/WireMailSwiftMailer.module on line 261
It looks like this condition is failing somehow: 
if ($this->transport != "Smtp" || $this->SMTPServer && $this->SMTPPort && $this->senderAddress) 
If I remove that line above (as well as the closing brace further in the function) then I no longer get errors.

So far I haven't been able to reproduce this. Will continue testing, though, since if it happened to you it's probably going to happen to others too. Shouldn't be too hard to figure out (*fingers crossed*).

3. The module version number shouldn't have preceding zeros, as this starts PHP thinking it's an octal number or something else (I don't recall). So version number should be 6 rather than 006.

I remember having problems remembering and "getting" the version number logic originally -- 006 was probably carried over from the time I first put this module together. Lately I've used integers, as that seems to be the expected thing there.

Slightly off-topic, perhaps, but integers still seem like a bad fit for version numbers to me. Version numbers should be able to go beyond 0-9 range.. and how do you represent versions such as 1.11.24 as an integer without actually using three sets of numbers?

Of course there's always the option of using strings in those cases, but I find it weird that integers are seen as "the default way" while they are only capable of representing some version numbers properly :)

  • Like 1

Share this post


Link to post
Share on other sites

So far I haven't been able to reproduce this. Will continue testing, though, since if it happened to you it's probably going to happen to others too. Shouldn't be too hard to figure out (*fingers crossed*).

Issue was quite obvious, actually: that "if" made sure that Swift Mailer wouldn't get initiated with SMTP transport unless it was properly configured. With the old logic this would've been fine, but not anymore, since local send() method is called regardless of whether Swift Mailer is available. Stupid mistake from me :)

I've changed this so that if you select SMTP transport but don't fill in required params (server and port), the module will fallback to Mail.

This (kind of) brings up another possible issue, though I'm not exactly sure how to deal with that yet: what to do when there's a connection issue in send()? Should that be caught and logged, should I throw an exception.. or is there even better alternative?

So far I'm thinking that an exception would be best way to handle this, so that apps / sites that rely on mail getting won't just continue like nothing happened.. though that might actually cause even more confusion.

Suggestions would be more than welcome :)

Share this post


Link to post
Share on other sites

@teppo: I think logging is mandatory, even if you throw an exception.

Also doing an automated fallback from SMTP to php-mail, without the users knowing isn't good in my opinion. Per default I would raise an error (and log it), but would give a configuration setting under advanced (or something) where the user have the possibility to enable that useful behave. If he check that option, _he_ has done so and not _you_, means he has at least be informed about that behave one times. :)

I'm a big fan of (automated) corrections for the user with missconfigurations, but with emails are a million possibilities given. Maybe on a company site they must use SMTP through a special company server to send company-internal messages, it could be that there are very restrictive settings and a mail from php-mail gets blocked and never reaching the recipients. (Sure, a rare case, but may be possible).

  • Like 4

Share this post


Link to post
Share on other sites

@horst: thanks for your input.. and your rare case is actually quite familiar for me, so I definitely get that :)

Fallback I mentioned earlier was actually intended as sort of an "installation helper", so that if you install the module on a server where PHP's mail() works (but you just don't want to use it or would prefer to use something else), it won't break anything. Running start, kind of.

Thinking about it now, a better solution for that might be setting the module to use Mail by default.. after that I could safely assume that if SMTP is selected but misconfigured, it's user error and exception should be thrown. This module can, after all, be used for Mail and Sendmail too, even though SMTP seems generally speaking most useful option and Mail definitely the least useful one..

Will have to give this some more thought, though. So far none of the options available seems to be clearly the best way to go. In any case you're definitely right in that it's not always possible (or even sensible for that matter) to attempt correcting mistakes user might've made.

  • Like 2

Share this post


Link to post
Share on other sites

I had some problems before that are all fixed now, somehow the following files where not transfered with FTP

/wire/core/WireMail.php

/wire/core/WireMailInterface.php

Installing and sending mail with SMTP worked fine now :)

Thanks for making this module available!

Edited by Raymond Geerts
  • Like 1

Share this post


Link to post
Share on other sites

@Raymond: Hi, this sounds that you have get the PW 2.4.0 stable. - If you have the right version, you must see at least a 2.4.1 in the backend

Version 4.3.1 isn't known. Current stable is 2.4.0 and DEV is 2.4.1

Edited by horst
  • Like 2

Share this post


Link to post
Share on other sites

Thanks horst, the problem was caused because WireMail and WireMailInterface classes where not uploaded by FTP somehow. Installing and sending works now.

I just only noticed that a form with multiple upload fields only makes the link to the first attachment available. The second attachment is always 0b and has no link. While in the FormBuilder Entries i can see both files uploaded correctly. Is this a bug in WireMail or the SwiftMailer class?

I have a form where the visitor can upload a CV and a Letter (both in doc, docx, pdf, rtf or txt format)

Share this post


Link to post
Share on other sites

@horst....Raymond is quoting what Ryan said. That was a typo (I believe, by Ryan), although he did it twice, which is baffling. See the post here

  • Like 2

Share this post


Link to post
Share on other sites

Ah, ok. (sorry @Raymond)

And also I cannot see the post in FormBuilder Forum, I believe! :)

Share this post


Link to post
Share on other sites

Thanks teppo, Ryan, Horst, et al :D

It looks seductively like a Lego solution might exist..? Seeing your module uses Swift Mailer and these guys note Swift Mailer at the top... I wonder if there is an easy way to use their service now, thanks to this Module?

Share this post


Link to post
Share on other sites

Hey Teppo, love the module, very smooth.

I did have problems setting the name for the "to" header, ie $mail->toName = $name, or $mail->to( $addr, $name ). Neither seemed to work for me. I've replaced the top of the ___init() function as follows to make this work, may be of some use to you:

public function ___send() {

    foreach( $this->to as $k => $v )
        $toAddr[$k] = $this->toName[$k];

    // create the message
    $message = Swift_Message::newInstance()
        ->setTo($toAddr)
        ->setSubject($this->subject); 

Thanks again for the module  :)

  • Like 1

Share this post


Link to post
Share on other sites

When installing module from Module Manager on version 2.4 I get this error on install, and when I try to visit the modules page.

 Error: Class 'WireMail' not found (line 19 of /home/gelburdg/public_html/site/modules/WireMailSwiftMailer/WireMailSwiftMailer.module) 

uploading module manually seeing if it fixes it. 

Share this post


Link to post
Share on other sites

@Neeks: which ProcessWire version are you using?

WireMail was introduced in ProcessWire 2.4.1, which means that you still need current dev branch to run it. I'm assuming that this is the problem. Either that, or there's something wrong with your ProcessWire installation (less likely).

Share this post


Link to post
Share on other sites

Thanks, sorry about that I just saw "compatability 2.4" under the module page, but after reading this forum post more I realize you do mention I need the latest dev branch. Will make sure to read the whole thread before posting next time. Thanks Teppo. 

Share this post


Link to post
Share on other sites

@teppo - does WireMailSwiftMailer support attachments?

Share this post


Link to post
Share on other sites

@Macrura: sorry for the slow reply, but.. no. This is loosely related to a discussion at GitHub, here: https://github.com/ryancramerdesign/ProcessWire/issues/566. I'd like to hear what Ryan has to say about CC, BCC and attachments before going and putting together custom solution for that.

My opinion is that all of these should be implemented in the base class (WireMail) so that WireMail module authors (at the moment meaning mostly me and Horst) don't have to cook up case-by-case solutions. Even if the modules still required some customisation and couldn't use WireMail features out of the box, at least we'd have compatible implementations.

  • Like 3

Share this post


Link to post
Share on other sites

On other news, I've just updated Swift Mailer bundled with the module from 5.0.3 to 5.2.1. This version includes a security fix, so anyone using this module should update. Note that the vulnerability doesn't affect this module; it's related to Reply-To, and this module doesn't, at the moment, use that in any way, but in case that someone is using the Swift Mailer library directly from this module's directory, that could still be a problem.

Other updates added just today include minor fixes and vastly improved tools for testing mailing capabilities (including a tool for sending test messages directly from module's configuration screen).

  • Like 5

Share this post


Link to post
Share on other sites

HI Teppo

I am struggling to send mail from my new site - worked fine on my local dev server, but not on the production server.

I have installed your module to try and see if that helps. But when I try and send a test mail (any transport method) it says

 A test message was just sent to 0 recipients

Any thoughts?

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Robin S
      Another little admin helper module...
      Template Field Widths
      Adds a "Field widths" field to Edit Template that allows you to quickly set the widths of inputfields in the template.

      Why?
      When setting up a new template or trying out different field layouts I find it a bit slow and tedious to have to open each field individually in a modal just to set the width. This module speeds up the process.
      Installation
      Install the Template Field Widths module.
      Config options
      You can set the default presentation of the "Field widths" field to collapsed or open. Field widths entered into the Template Field Widths inputfield are only applied if the Edit Template form is submitted with the Template Field Widths inputfield in an opened state. "Collapsed" is the recommended setting if you think you might also use core inputs for setting field widths in a template context. You can choose Name or Label as the primary identifier shown for the field. The unchosen alternative will become the title attribute shown on hover. You can choose to show the original field width next to the template context field width.  
      https://github.com/Toutouwai/TemplateFieldWidths
      https://modules.processwire.com/modules/template-field-widths/
    • By adrian
      Tracy Debugger for ProcessWire
      The ultimate “swiss army knife” debugging and development tool for the ProcessWire CMF/CMS

       
      Integrates and extends Nette's Tracy debugging tool and adds 35+ custom tools designed for effective ProcessWire debugging and lightning fast development
      The most comprehensive set of instructions and examples is available at: https://adrianbj.github.io/TracyDebugger
      Modules Directory: http://modules.processwire.com/modules/tracy-debugger/
      Github: https://github.com/adrianbj/TracyDebugger
      A big thanks to @tpr for introducing me to Tracy and for the idea for this module and for significant feedback, testing, and feature suggestions.
    • By adrian
      This module allows you to automatically rename file (including image) uploads according to a configurable format
      This module lets you define as many rules as you need to determine how uploaded files will be named and you can have different rules for different pages, templates, fields, and file extensions, or one rule for all uploads. Renaming works for files uploaded via the admin interface and also via the API, including images added from remote URLs.   Github: https://github.com/adrianbj/CustomUploadNames
      Modules Directory: http://modules.processwire.com/modules/process-custom-upload-names/
      Renaming Rules
      The module config allows you to set an unlimited number of Rename Rules. You can define rules to specific fields, templates, pages, and file extensions. If a rule option is left blank, the rule with be applied to all fields/templates/pages/extensions. Leave Filename Format blank to prevent renaming for a specific field/template/page combo, overriding a more general rule. Rules are processed in order, so put more specific rules before more general ones. You can drag to change the order of rules as needed. The following variables can be used in the filename format: $page, $template, $field, and $file. For some of these (eg. $field->description), if they haven't been filled out and saved prior to uploading the image, renaming won't occur on upload, but will happen on page save (could be an issue if image has already been inserted into RTE/HTML field before page save). Some examples: $page->title mysite-{$template->name}-images $field->label $file->description {$page->name}-{$file->filesize}-kb prefix-[Y-m-d_H-i-s]-suffix (anything inside square brackets is is considered to be a PHP date format for the current date/time) randstring[n] (where n is the number of characters you want in the string) ### (custom number mask, eg. 001 if more than one image with same name on a page. This is an enhanced version of the automatic addition of numbers if required) If 'Rename on Save' is checked files will be renamed again each time a page is saved (admin or front-end via API). WARNING: this setting will break any direct links to the old filename, which is particularly relevant for images inserted into RTE/HTML fields. The Filename Format can be defined using plain text and PW $page variable, for example: mysite-{$page->path} You can preserve the uploaded filename for certain rules. This will allow you to set a general renaming rule for your entire site, but then add a rule for a specific page/template/field that does not rename the uploaded file. Just simply build the rule, but leave the Filename Format field empty. You can specify an optional character limit (to nearest whole word) for the length of the filename - useful if you are using $page->path, $path->name etc and have very long page names - eg. news articles, publication titles etc. NOTE - if you are using ProcessWire's webp features, be sure to use the useSrcExt because if you have jpg and png files on the same page and your rename rules result in the same name, you need to maintain the src extension so they are kept as separate files.
      $config->webpOptions = array(     'useSrcExt' => false, // Use source file extension in webp filename? (file.jpg.webp rather than file.webp) ); Acknowledgments
      The module config settings make use of code from Pete's EmailToPage module and the renaming function is based on this code from Ryan: http://processwire.com/talk/topic/3299-ability-to-define-convention-for-image-and-file-upload-names/?p=32623 (also see this post for his thoughts on file renaming and why it is the lazy way out - worth a read before deciding to use this module). 
       
       
      NOTE:
      This should not be needed on most sites, but I work with lots of sites that host PDFs and photos/vectors that are available for download and I have always renamed the files on upload because clients will often upload files with horrible meaningless filenames like:
      Final ReportV6 web version for John Feb 23.PDF

×
×
  • Create New...