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

@horst @kongondo : i was quoting Ryan, before i edited my post. But indeed the dev branche version is 2.4.1

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

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.

  • Similar Content

    • By MoritzLost
      This is a new module that provides a simple solution to clearing all your cache layers at once, and an extensible interface to perform various cache-related actions.
      The simple motivation behind this module was that I was tired of manually clearing caches in several places after deploying a change on a live site. The basic purpose of this module is a simple Clear all caches link in the Setup menu which clears out all caches, no matter where they hide. You can customize what exactly the module does through it's configuration menu:
      Expire or delete all cache entries in the database, or selectively clear caches by namespace ($cache API) Clear the the template render cache. Clear out specific folders inside your site's cache directory (/site/assets/cache) Refresh version strings for static assets to bust client-side browser caches (this requires some setup, see the full documentation for details). This is the basic function of the module. However, you can also add different cache management action through the API and execute them through the module's interface. For this advanced usage, the module provides:
      An interface to see all available cache actions and execute them. A system log and logging output on the module page to see verify what the module is doing. A CacheControlTools class with utility functions to clear out different caches. An API to add cache actions, execute them programmatically and even modify the default action. Permission management, allowing you granular control over which user roles can execute which actions. The complete documentation can be found in the module's README.
      Beta release
      Note that I consider this a Beta release. Since the module is relatively aggressive in deleting some caches, I would advise you to install in on a test environment before using it on a live site.
      Let me know if you're getting any errors, have trouble using the module or if you have suggestions for improvement!
      In particular, can someone let me know if this module causes any problems with the ProCache module? I don't own or use it, so I can't check. As far as I can tell, ProCache uses a folder inside the cache directory to cache static pages, so my module should be able to clear the ProCache site cache as well, I'd appreciate it if someone can test that for me.
      Future plans
      If there is some interest in this, I plan to expand this to a more general cache management solution. I particular, I would like to add additional cache actions. Some ideas that came to mind:
      Warming up the template render cache for publicly accessible pages. Removing all active user sessions. Let me know if you have more suggestions!
      Links
      https://github.com/MoritzLost/ProcessCacheControl ProcessCacheControl in the Module directory

    • By joshua
      This module is (yet another) way for implementing a cookie management solution.
      Of course there are several other possibilities:
      - https://processwire.com/talk/topic/22920-klaro-cookie-consent-manager/
      - https://github.com/webmanufaktur/CookieManagementBanner
      - https://github.com/johannesdachsel/cookiemonster
      - https://www.oiljs.org/
      - ... and so on ...
      In this module you can configure which kind of cookie categories you want to manage:

      You can also enable the support for respecting the Do-Not-Track (DNT) header to don't annoy users, who already decided for all their browsing experience.
      Currently there are four possible cookie groups:
      - Necessary (always enabled)
      - Statistics
      - Marketing
      - External Media
      All groups can be renamed, so feel free to use other cookie group names. I just haven't found a way to implement a "repeater like" field as configurable module field ...
      When you want to load specific scripts ( like Google Analytics, Google Maps, ...) only after the user's content to this specific category of cookies, just use the following script syntax:
      <script type="optin" data-type="text/javascript" data-category="statistics" data-src="/path/to/your/statistic/script.js"></script> <script type="optin" data-type="text/javascript" data-category="marketing" data-src="/path/to/your/mareketing/script.js"></script> <script type="optin" data-type="text/javascript" data-category="external_media" data-src="/path/to/your/external-media/script.js"></script> <script type="optin" data-type="text/javascript" data-category="marketing">console.log("Inline scripts are also working!");</script> The type has to be "optin" to get recognized by PrivacyWire, the data-attributes are giving hints, how the script shall be loaded, if the data-category is within the cookie consents of the user. These scripts are loaded asynchronously after the user made the decision.
      If you want to give the users the possibility to change their consent, you can use the following Textformatter:
      [[privacywire-choose-cookies]] It's planned to add also other Textformatters to opt-out of specific cookie groups or delete the whole consent cookie.
      You can also add a custom link to output the banner again with a link / button with following class:
      <a href="#" class="privacywire-show-options">Show Cookie Options</a> <button class="privacywire-show-options">Show Cookie Options</button> This module is still in development, but we already use it on several production websites.
      You find it here: https://github.com/blaueQuelle/privacywire/tree/master
      Download: https://github.com/blaueQuelle/privacywire/archive/master.zip
      I would love to hear your feedback 🙂
      Edit: Updated URLs to master tree of git repo
       
    • By David Karich
      Admin Page Tree Multiple Sorting
      ClassName: ProcessPageListMultipleSorting
      Extend the ordinary sort of children of a template in the admin page tree with multiple properties. For each template, you can define your own rule. Write each template (template-name) in a row, followed by a colon and then the additional field names for sorting.
      Example: All children of the template "blog" to be sorted in descending order according to the date of creation, then descending by modification date, and then by title. Type:
      blog: -created, -modified, title  Installation
      Copy the files for this module to /site/modules/ProcessPageListMultipleSorting/ In admin: Modules > Check for new modules. Install Module "Admin Page Tree Multible Sorting". Alternative in ProcessWire 2.4+
      Login to ProcessWire backend and go to Modules Click tab "New" and enter Module Class Name: "ProcessPageListMultipleSorting" Click "Download and Install"   Compatibility   I have currently tested the module only under PW 2.6+, but think that it works on older versions too. Maybe someone can give a feedback.     Download   PW-Repo: http://modules.processwire.com/modules/process-page-list-multiple-sorting/ GitHub: https://github.com/FlipZoomMedia/Processwire-ProcessPageListMultipleSorting     I hope someone can use the module. Have fun and best regards, David
    • By dimitrios
      Hello,
      this module can publish content of a Processwire page on a Facebook page, triggered by saving the Processwire page.
      To set it up, configure the module with a Facebook app ID, secret and a Page ID. Following is additional configuration on Facebook for developers:
      Minimum Required Facebook App configuration:
      on Settings -> Basics, provide the App Domains, provide the Site URL, on Settings -> Advanced, set the API version (has been tested up to v3.3), add Product: Facebook Login, on Facebook Login -> Settings, set Client OAuth Login: Yes, set Web OAuth Login: Yes, set Enforce HTTPS: Yes, add "https://www.example.com/processwire/page/" to field Valid OAuth Redirect URIs. This module is configurable as follows:
      Templates: posts can take place only for pages with the defined templates. On/Off switch: specify a checkbox field that will not allow the post if checked. Specify a message and/or an image for the post.
      Usage
      edit the desired PW page and save; it will post right after the initial Facebook log in and permission granting. After that, an access token is kept.
       
      Download
      PW module directory: http://modules.processwire.com/modules/auto-fb-post/ Github: https://github.com/kastrind/AutoFbPost   Note: Facebook SDK for PHP is utilized.


×
×
  • Create New...