email::sender::simple is brewing
If I were going to was introspective, I’d say that one of my best and worst qualities is my love of designing something for ages before building it. I think it tends to make my end product better, but it also means that the product languishes. Right now, that’s the state of Email::Sender::Simple.
Email::Sender is my replacement for Email::Send. It was planned for about two years before it was released, and when it was released, it contained the notice that Email::Sender::Simple would be included in a future version to reduce the number of decisions for the end-user to make. After all, the end user does not usually want to think about how his email is tramsmitted.
Right now, the Email-Sender repo has a young version of Email::Sender::Simple in it. It’s meant to steal the best things about Email::Send, Email::Sender::Transport, MIME::Lite, and (Pobox’s own) ICG::Sendmail. It simplifies things in a number of ways, some of which end up being incredibly powerful, based on our usage of ICG::Sendmail.
For one, you never need to worry about what transport you want to use. There
are sane defaults (like MIME::Lite tries to provide), and they can be
overridden by a subclass or the environment. The environment override is a
fantastically powerful tool, and probably the best part of ICG::Sendmail. When
EMAIL_SENDER_TRANSPORT
is set, no other transport but the one identified
there will be used. This means that any program in our world can be run like
this:
walrus!rjbs% EMAIL_SENDER_TRANSPORT=Maildir generate-activity-report xyzzy
Everything will happen as usual, but the mail will be sent to ./Maildir
instead of SMTP. It’s also trivial to set that environment variable at BEGIN
time inside your test scripts and have messages delivered in memory. Do your
tests run subprocesses or fork? No problem, you can use the SQLite transport
and inspect all deliveries across all subprocesses.
I think that, released now, Email::Sender::Simple would be great. That said, there are still a bunch of design questions up in the air – and I’m going to keep obsessing about them for a while. I’m hoping to have it all decided in time for my email talk at YAPC this year. Here are some of my current quandaries.
Right now Email::Sender::Transport is the most important class in Email-Sender.
It has two vital methods: send
and send_email
. The first is what users
call. It does a bunch of stuff like convert all kinds of input into an
Email::Abstract, sanitychecks the envelope, and so on. Then it calls
send_email
, which is what most transports are expected to provide. I think
that this behavior belongs in a role, but refactoring Email::Sender::Simple
and Email::Sender::Transport with minimal chaos.
Should Simple return a bool or should it throw an exception? I’m nearly entirely sure that I want it to throw. Email::Send soured me on return values for non-predicates.
How will other senders signal to Simple that they’re not suitable for use by
it? I never want to allow Simple to signal partial success (ugh!) so right
now I just check for something like can_signal_partial_success
. I think
instead I want to just check suitable_for_simple
.
What are some common ways people will extend Simple? ICG::Sendmail has some built-in magic to do things like make it easy to save copies of sent mail. Hopefully the refactoring can make it easy to plug this in with subclasses, roles, and method modifiers.
Anyway, there’s a lot of obsessing still to be done, but hopefully it will all pay off before the end of the summer, and I will finally be able tell people to stop using Email::Send for good.