On Wed, Feb 13, 2013 at 2:40 PM, Jeremie BOUSQUET
<
jeremie.bousquet(a)gmail.com> wrote:
Hi,
Reviving this thread, because I wonder how multiparts are managed ...
More precisely, nowhere in current mailsender API do we choose the type
of
multipart to manage (ie, multipart/mixed,
multipart/alternative...). From
what is said above, and the api signatures, it seems that by default the
component will generate mails with multipart/alternative content, which
may
be most common use-case.
Yes, this is multipart/alternative content I create
If it's multipart/alternative, then calling:
$mail.addContent("text1", "plain/text")
$mail.addContent("text2", "plain/text")
$mail.addContent("text3", "plain/html")
... has very little meaning. A multipart alternative is supposed to
present
alternative representations of the same
information, most usual use-case
being to provide text and html parts. The client is supposed to display
the
last part he can handle (ie, pure text client
would display the text
part,
and html capable client will display the html
part).
Indeed with what I have implemented so far, this has very little meaning. I
considered that people that were going to use addContent and not directly
one of the method like $services.mailSender.sendMail(to, html, alternative
text) would be aware of that (of course this should be explicitly said in
the doc). But I agree that we could perhaps consider letting them choose
between multipart/alternative and multipart/mixed for example. I'm just
afraid that it would make the component harder to understand and to use.
I agree with you, most important is to know what to expect. Managing all
multiparts types would make the component very complex I believe, for
little added-value.
When there are several calls to addContent(...) for the same content
type,
is provided text appended to content already
present in existing part ?
Ie, in sample above, I would get an email with a plain/text part
containing
"text1text2" and an html part with
"text3" ?
If text/plain parts are added instead of concatenated, then in sample
below, it would mean that "text2" would obliterate "text1" added
before,
as
it will maybe never be displayed by the client
(depending on how the
client
interprets this case).
Another thing, when you add html content to an email, it's usually for
its
better formatting features compared to plain
text. A common use-case (for
example, if you want to send a newsletter), is to include some images in
the html page sent.
To do that, you can't just provide the html content, then some attached
images. Doing that you can only send an html page (without inline images)
and images attached. To send an html document with inline image, you need
to send a multipart/related, instead of a "text/html" part, and generate
content-ids for each image/attachment.
Is it managed by the mail sender ?
When I have a text/html mime part, I parse it for finding things like src
:cid and create a multipart/related part in order to embed the image in the
HTML. So I guess it's fine from this point of view.
By the way, I've just put my current mailSender code on a contrib repo :
https://github.com/xwiki-contrib/xwiki-platform-mail. I should still clear
up a few things in it (had to make some strange thing to get rid of class
fan out issues... I would take care of it as soon as I have time to,
hopefully next week) before it is publishable but it is supposed to work (I
tested it locally) and it would at least enable you to see how things are
done. Don't hesitate to comment it, and let me know what you think should
be changed !
No pb, even if I'm not an email expert in any way ;-) But I think I will
use your component as client when I'll implement the reply feature in Mail
Archive app, at that time it will be easier to challenge it against my own
use-cases.
What I just saw very quickly:
- I wonder if DefaultMailSenderUtils#getDocumentRef(String docName) is not
the same as DocumentReferenceResolver#resolve() ?
- from MimePartCreator#createAttachmentPart(), you create a temporary file
in order to create the MimeBodyPart, maybe you could use a
BufferedDataSource to avoid that ?
- from MimePartCreator#createHtmlPart(), you use a pattern to find inline-d
attachments ("cid:") : src=('|\")cid:([^'\"]*)('|\")
...but in HTML nothing prevents from having "src = 'cid:...'" (with
white
spaces), that would not be match by that pattern.
Also, I'm not sure I understand well, but it seems to consider that file
name is what is in the "cid:*" value, but it's usually not the case
(usually, content-id is a unique id built from filename, both values being
provided as Content-Id and filename headers).
- you call MimePartCreator#createAttachmentPart() for both types of
attachments ("embedded images", and all other attachments), but
"INLINE_DISPOSITION" is used as disposition for all of them. I think
non-embedded attachments should have a disposition of ATTACHMENT. It's not
so important though as anyway clients do whatever they like with your
attachments.
- currently it seems not to manage possibility to send a mail with a
"Sender:" different than "From:" header. It is sometimes useful, for
example in mailing-lists, usually "From:" is the human person who is
sending the mail, and "Sender:" is the mailing-list server that effectively
sends it to mailing-list recipients. For SMTP servers that allow that, it
is then possible to send mails from a unique account (the sender) "on
behalf of" the real users (in from/to), if it has the rights to do so of
course.
By the way it
would be quite nice, to be able to round-trip between an
XWiki page content (html) and a multipart/related part. I wonder how it
is
managed by Newsletter Application...
Using mail Templates enables you to include some Wiki content in it.
Perhaps it is what the Newsletter application uses ?
Cheers,
Thomas
Note: concerning the "mail parser" implemented in Mail Archive app,
currently, it does not differentiate multipart/related,
multipart/alternative and multipart/mixed. The same process applies: all
"text/html" parts are parsed into a unique concatenated html content, all
"text/plain" parts are parsed into a unique concatenated pure text
content.
If some attachments have content-ids, their
reference are replaced in the
html content by a link to proper attached file. This almost respects
RFC1341, in that it almost considers all multiparts as "mixed" (but not
in
sequence, as text and html are grouped together).
The resulting display
is
fine in 99,99% of cases, as far as I tested.
BR,
Jeremie
2013/1/7 Thomas Mortagne <thomas.mortagne(a)xwiki.com>
> On Mon, Jan 7, 2013 at 12:12 AM, Vincent Massol <vincent(a)massol.net>
> wrote:
> >
> > On Jan 6, 2013, at 10:54 PM, Thomas Delafosse <
> thomas.delafosse(a)xwiki.com> wrote:
> >
> >> The advantage of jSoup is that it handles the problems I could have
if
> the
> >> html part is not well written,
> >
> > Actually this is exactly what the XWiki HTML parser does too :)
> >
> > I really think you should use our parser.
>
> Plus de HTML parser is very important so the more we test it the
better.
>
> Thanks
> -Vincent
>
>> so I was thinking it was more secure to use
>> it than just parsing the "<>" in the html part . But I must
admit
that I
> >> haven't had a close look on the xwiki renderers, and if there are
some
that
>> do it well, I should probably rather use them... I will give it a
closer
> look
tomorrow.
>
> Cheers,
>
> Thomas
>
> On Sun, Jan 6, 2013 at 8:53 AM, Jeremie BOUSQUET <
jeremie.bousquet(a)gmail.com
>>> wrote:
>>
>>> Le 2 janv. 2013 18:44, "Thomas Delafosse" <
thomas.delafosse(a)xwiki.com>
> a
> >>> écrit :
> >>>>
> >>>> On Fri, Dec 28, 2012 at 9:01 PM, Sergiu Dumitriu <
sergiu(a)xwiki.org>
> >>> wrote:
> >>>>
> >>>>> On 12/26/2012 10:18 AM, Vincent Massol wrote:
> >>>>>>
> >>>>>> On Dec 26, 2012, at 4:01 PM, Thomas Delafosse <
> >>>>> thomas.delafosse(a)xwiki.com> wrote:
> >>>>>>
> >>>>>>> On Wed, Dec 26, 2012 at 3:23 PM, Vincent Massol <
> vincent(a)massol.net
> >>>>
> >>>>> wrote:
> >>>>>>>
> >>>>>>>>
> >>>>>>>> On Dec 26, 2012, at 3:15 PM, Thomas Delafosse <
> >>>>> thomas.delafosse(a)xwiki.com>
> >>>>>>>> wrote:
> >>>>>>>>
> >>>>>>>>> Ok, so I would rather have a component API
like
> >>>>>>>>>
> >>>>>>>>> - Mail prepareMail(from, to, cc, bcc, subject)
> >>>>>>>>
> >>>>>>>> createMail is better than prepareMail IMO.
> >>>>>>>>
> >>>>>>>> I'd make the cc and bcc not part of the
constructor and
instead
> >>> move
> >>>>> them
> >>>>>>>> as setters since they're optional.
> >>>>>>>>
> >>>>>>>>> - int sendMail(Mail mail)
> >>>>>>>>
> >>>>>>>> Either that or add a send() method in Mail.
> >>>>>>>>
> >>>>>>>>> while the methods addToContent, addHtml,
addAttachment,
etc...
>>> would
>>>>> be
>>>>>>>>> directly used from the Mail class.
>>>>>>>>
>>>>>>>> I don't understand what addToContent is and what
different it
has
> >>> to
> >>>>>>>> addHtml.
> >>>>>>>>
> >>>>>>>
> >>>>>>> addToContent (String mimeType, String partToAdd) is
more
generic
:
> >>> you
> >>>>>>> specify the Mime Type of the part you want to add. So
> addHtml(String
> >>> s)
> >>>>> is
> >>>>>>> just the same as addToContent("text/html",
s). But as most of
the
>>> time
>>>>> you
>>>>>>> add only Html or text, I was thinking it was better to have
a
>>> specific
>>>>>>> method to add an Html part in the scripting API. I can do
the
same
> >>> with
> >>>>> a
> >>>>>>> addTextContent method.
> >>>>>>
> >>>>>> I think I prefer addContent instead of addToContent.
> >>>>>>
> >>>>>> So just to be sure, doing the following will work:
> >>>>>>
> >>>>>> addContent("content1", "text")
> >>>>>> addContent("content2", "text")
> >>>>>> addContent("content3", "html")
> >>>>>>
> >>>>>> right?
> >>>>>>
> >>>>>> It's going to create a multipart email?
> >>>>>>
> >>>>>> I think a single addContent method is good enough, passing
an
enum
as
>>>>> the second parameter (the mimetype). Enums are magically
constructed
>>
from
>>>> velocity with our custom uberspector.
>>>>
>>>> -1 for enums. That limits the possible content types we can add.
>>>>
>>>
>>> I agree on that point : there are simpler methods such as
>>> $services.mailSender.sendHtmlMail(from, to, subject, html,
alternative)
>>> for
>>>> people who don't know much about mimeTypes, so it would be a shame
to
> >>> limit
> >>>> this method.
> >>>>
> >>>>>
> >>>>> I prefer:
> >>>>>
> >>>>> addMimePart(String content, string mimeType)
> >>>>>
> >>>>>
> >>>> So far it's exactly the way my addContent method works. But I
can
> change
> >>>> its name to addMimePart if you prefer.
> >>>>
> >>>>
> >>>>> There's also a MimePart in the standard javax.mail library,
and
we
> >>> could
> >>>>> actually use this one, since it's more standard, and more
flexible:
http://javamail.kenai.com/nonav/javadocs/javax/mail/internet/MimePart.html
http://javamail.kenai.com/nonav/javadocs/javax/mail/internet/MimeBodyPart.h…
> >>>>>
> >>>>> But this might be a bit too verbose and complex to use.
> >>>>>
> >>>>> I hope that the implementation will be smart enough to send a
plain
> >>>>> message when only one
body part (of type text or html) is
present.
>>>>>
>>>>>
>>>> If there is only a text or html part to the mail, I add an
alternative
> >>>> text/plain part to the mail, using jSoup to convert the html
content
into
>>>> text, if it's what you mean.
>>>
>>> On mail reader side, I used xwiki parsers/renderers to convert html
to
>>> plain text. What is added value of
jsoup ?
>>>
>>>>
>>>>>>> Can I call addContent several times?
>>>>>>>>
>>>>>>>
>>>>>>> Yes, so for example if you want to have an email with an
html
part
> >>> and a
> >>>>>>> calendar part, you call
addToContent("text/html", html Text)
and
>>> then
>>>>>>> addToContent("text/calendar", calendar Code).
>>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>>> So a use-case would rather be :
>>>>>>>>> {{velocity}}
>>>>>>>>> $mail = $services.mailSender.prepareMail(from,
to,...)
>>>>>>>>> $mail.addHtml('<p>Blabla</p>')
>>>>>>>>
>>>>>>>> addHTMLContent would be nicer. So you need also a
addTextContent?
> >>>>>>>> why not have an addContent(String, boolean isHTML)
> >>>>>>>> or a more generic addContent(String, String
mimeType)
> >>>>>>>> or both
> >>>>>>>>
> >>>>>>>>> $mail.addCalendar()
> >>>>>>>>
> >>>>>>>> What is a calendar?
> >>>>>>>>
> >>>>>>>
> >>>>>>> It is either a vCalendar or an iCalendar (it is used by
Gmail
to
>>> send
>>>>>>> invitations). It corresponds to the Mime Type
"text/calendar".
Here
>>>> again
>>>>>> addCalendar(String calendar) is just the same as
>>>>>> addToContent("text/calendar", calendar). It's just
to make it
easier
>>> to
>>>>>>> use.
>>>>>>
>>>>>> ok. So I think in the future we could add some calendar helper
that
> >>> will
> >>>>> create the calendar string information.
> >>>>>
> >>>>> -1 for a specific addCalendar method. Why not addVCard,
addImage,
> >>>>> addPDF, addDoc and so on? This makes a stuffed API, where
anything
> that
> >>>>> doesn't have a dedicated API method will feel like a
second-class
> >>>>> citizen.
> >>>>
> >>>>
> >>>>>> For now this is good enough IMO:
> >>>>>> addContent("calendar info content as per RFC
2445", "calendar")
> >>>>>>
> >>>>>> And then later on something like:
> >>>>>>
> >>>>>> addContent($mailsender.createCalendarMimeTypeData(param1,
param2,
> >>> ….),
> >>>>> "calendar")
> >>>>>>
> >>>>>>>> You should also show an example when using the Java
API.
> >>>>>>>>
> >>>>>>>
> >>>>>>> On Java it would give something like :
> >>>>>>>
> >>>>>>> @Inject
> >>>>>>> private MailSender mailSender
> >>>>>>>
> >>>>>>> Mail mail = this.mailSender.newMail(from,to,subject) ;
> >>>>>>
> >>>>>> I don't like this too much. Why not use a constructor
on the
Mail
>>> object?
>>>>>
>>>>> Constructors are bad, in a component-based world. I'd rather
have
the
>>>>> Mail object an interface,
with an internal implementation used by
the
> >>>>> MailSender implementation.
> >>>>>
> >>>>>> (The other option is a perlookup component is you really
need to
> have
> >>>>> some other components injected in the Mail object; in that
case
> you'll
> >>> need
> >>>>> setters to from/to/subject since we currently don't
support
> constructor
> >>>>> injection).
> >>>>>>
> >>>>>>> String htmlCode = "<p>Blabla</p>"
;
> >>>>>>> String calendar = "BEGIN VCALENDAR... END
VCALENDAR" ;
> >>>>>>> mail.addToContent("text/html", htmlCode) ;
> >>>>>>> mail.addToContent("text/calendar", calendar)
;
> >>>>>>> this.mailSender.sendMail(mail) ;
> >>>>>>
> >>>>>> why sendMail and not send? We're in a MailSender
component so we
> know
> >>>>> we're sending mail already ;)
> >>>>>
> >>>>> +1 for send.
> >>>>>
> >>>>> By the way, I've put a first version of my component on
github :
> >>>>
https://github.com/tdelafosse/mailSender. Feel free to have a
look
and
>> to
>>> tell me if there's things to change / add / enhance.
>>>
>>> Cheers,
>>>
>>> Thomas
_______________________________________________
devs mailing list
devs(a)xwiki.org
http://lists.xwiki.org/mailman/listinfo/devs
--
Thomas Mortagne
_______________________________________________
devs mailing list
devs(a)xwiki.org
http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________
devs mailing list
devs(a)xwiki.org
http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________
devs mailing list
devs(a)xwiki.org
http://lists.xwiki.org/mailman/listinfo/devs