Send multiple attachments with Grails Async Mail Plugin - email

I am using grails Async Mail plugin to send emails with attachments in my app. to achieve that I have written following code
def sendEmail = {
def documentsInstances = Documents.getAll(params.list('ids[]'))
def s3Service = new AmazonS3Service()
documentsInstances.each(){documentsInstance->
asyncMailService.sendMail {
multipart true
to documentsInstance.author.emailAddress
subject 'Test';
html '<body><u>Test</u></body>';
attachBytes documentsInstance.filename , 'text/plain', s3Service.getBytes(session.uid,documentsInstance.filename);
}
}//
}
Now the code above works pretty much correctly but it sends an email per attachment, I am not sure how can I move this loop inside send mail so that I can send multiple attachments in an email.
Also is there a way to send an email so that I don't have to load a whole file in byte[]?
I am using JetS3t for access to Amazon S3 and I tried "attach" method with
new InputStreamResource(s3Obj.getDataInputStream()) ie
attach documentsInstance.filename , 'text/plain', new InputStreamResource(s3Obj.getDataInputStream());
but I am getting
"Passed-in Resource contains an open stream: invalid argument. JavaMail requires an InputStreamSource that creates a fresh stream for every call"

You need your loop inside the email:
def sendEmail = {
def documentsInstances = Documents.getAll(params.list('ids[]'))
def s3Service = new AmazonS3Service()
asyncMailService.sendMail {
multipart true
to documentsInstance.author.emailAddress
subject 'Test';
html '<body><u>Test</u></body>';
// loop over attachments
documentsInstances.each{ documentsInstance->
attachBytes documentsInstance.filename , 'text/plain', s3Service.getBytes(session.uid, documentsInstance.filename);
}
}
}
This should attach multiple files.
If it throws an error about not being able to find an attachBytes method, you might need to explicitly call owner.attachBytes instead, which should refer to the outer sendMail closure.
Update based on comments:
The Async plugin looks like it defers to the normal mail plugin. The normal mail plugin's docs describes how to use multiple attachments.
This would look something like:
// loop over attachments
documentsInstances.each{ documentsInstance->
attach documentsInstance.filename , 'text/plain', s3Service.getBytes(session.uid, documentsInstance.filename);
//^^^^^^ Notice, just 'attach', not 'attachBytes'
}
I don't know the S3 plugin you are using, but if there is a way to retrieve an InputStreamSource from it, it appears that you can stream the bytes directly to the mail plugin, instead of loading them into memory.

Related

TypeError: send_mail() missing 3 required positional arguments: 'message', 'from_email', and 'recipient_list'

so I'm wanting to make this form where the client fills their name, email and a message. Then that message and their name is sent to my mail address and another mail is sent from my address to the clients one telling that their mail was sent successfully.
I already did this on another project and literally just copied changing the name of the functions n stuff but it doesn't work.
views.py
def send_email(email):
context = {'email': email}
template = get_template('emails/message-confirmation.html')
content = template.render(context)
email = EmailMultiAlternatives(
'Test email',
'AmiSalta message confirmation',
settings.EMAIL_HOST_USER,
[email]
)
email.attach_alternative(content, 'text/html')
email.send()
def function(request):
form = ContactForm_es()
if request.method == 'POST':
email = request.POST.get('email')
send_mail(email)
form = ContactForm_es(request.POST)
if form.is_valid():
email = form.cleaned_data['email']
full_name = form.cleaned_data['full_name']
body = form.cleaned_data['body']
send_mail(full_name,body,email, ['******#gmail.com'])
return render(request, 'es/home.html', {
'form': form,
})
I'm going crazy bc is the last thing I need to do and I already did once but I just can't make it work. Please if someone knows what's wrong let me know, thanks in advance.
I was getting the same issue you are having and the thing I was doing wrong was in the URLs.py file I was calling send_mail directly instead of the veiw_func that sends the mail that is why it was saying all the three required parameters are missing.
check your URLs.py file you might be having the same issue
Check if you use your send_email in urls.py instead of send_mail. The name of your function is very similar to the django's send_mail() function. You can easily confuse yourself.
Change the name of function def send_email(email): to something def mailtest(email):
you are getting thise error beacause
you are trying to overwrite the function

How to get the "body" and "subject" fields of a draft when extending compose UI?

We are developing a Gmail Addon in which we extend the compose UI.
This extends the compose window in which you can compose your e-mail.
We need the 'From', 'To', 'Subject' and 'Body' of the message that is being composed.
The 'From' can be read from the Session object like this
var mySelf = Session.getEffectiveUser().getEmail();
The 'To' can be read from the draftMetadata from the event object of the function being called.
function composeEmail(event) { console.log(event.draftMetadata.toRecipients); }
The 'Subject' and 'Body' can't be read from the event object of the function since it is a composeTrigger. The argument contains these objects:
{
formInput = {},
clientPlatform = web,
formInputs = {},
parameters = {},
draftMetadata = {
toRecipients = [test #test.com],
subject = ,
bccRecipients = [],
ccRecipients = []
}
}
Surprisingly to me, the subject key is there but not being filled in (yes I did type in a subject).
Question:
How can I get the 'Subject' and 'Body' of the E-mail being composed by the user in the extended composer UI?
Extra information:
The contextual trigger action contains the following object as event object:
{
clientPlatform = web,
messageMetadata = {
messageId = 16e agg7323451256989f68,
accessToken = AAGdOAawdaAOW8PWchmdawdk0N13STKnBPMAOXVjZVHyQMfAawdBtgEIrS6N8y5h2BOZnKFPlfsl5VBsyPiF7YiONOoP7XVjKZawdi - E6vI - jVU92dPmfj3RNmXfawdawdeaNMrXehAFLm
}
}
By reading an email through the contextual trigger a messageId is being added in which the getBody and getSubject methods can be used.
As of now, the Compose Trigger Event never returns the value of the subject field.
I have filled a bug for this here. Click the ★ icon to follow this Issue and get updates. This will also help prioritize this Issue.
As a workaround, you can use the contextual trigger to:
Get the messageId
Find drafts that have that messageId associated to them
Get the draft by their draftId
Fetch the subject line from the Headers object on the draft.
This only works on drafts that are replying to a specific message.
I've never done this before so this is a guess. I looked at the compose dialog html with the developer tools and this is what I noticed.
There seem to be a bunch of hidden inputs that are used to store values that are typed into the compose dialog. So I would try something like:
formInputs.body or perhaps formInput.body taking the name of the key from names of this hidden elements. This is just a guess.

Add Email Signature to Email Notification Script

I am writing a code on Google Apps Script to send an email every time there is a new announcement made in my site. Here is the code for reference:
var url_of_announcements_page = "https://sites.google.com/announcements";
var who_to_email = "emailaccount";
function emailAnnouncements(){
var page = SitesApp.getPageByUrl(url_of_announcements_page);
if(page.getPageType() == SitesApp.PageType.ANNOUNCEMENTS_PAGE){
var announcements = page.getAnnouncements({ start: 0,
max: 10,
includeDrafts: false,
includeDeleted: false});
announcements.reverse();
for(var i in announcements) {
var ann = announcements[i];
var updated = ann.getLastUpdated().getTime();
if (updated > PropertiesService.getScriptProperties().getProperty("last-update")){
var options = {};
options.htmlBody = Utilities.formatString("<h1><a href='%s'>%s</a></h1>%s", ann.getUrl(), ann.getTitle(), ann.getHtmlContent());
MailApp.sendEmail(who_to_email, "Announcement - '"+ann.getTitle()+"'", ann.getTextContent()+"\n\n"+ann.getUrl(), options);
PropertiesService.getScriptProperties().setProperty('last-update',updated);
}
}
}
}
function setup(){
PropertiesService.getScriptProperties().setProperty('last-update',new Date().getTime());
}
I would like to know if it is possible to add my gmail signature to the code. As when I send it with the script my signature is removed. Do I have to make my signature in the code or am i able to get my signature from gmail and automatically insert it at the end? Here is the line for the formatting of the email:
MailApp.sendEmail(who_to_email, "Announcement - '"+ann.getTitle()+"'", ann.getTextContent()+"\n\n"+ann.getUrl(), options);
Apps Script cannot access user's signature: there is no method for that in MailApp, or GmailApp, or even in Gmail API accessible via Advanced Google Services.
In principle, you could use GmailApp to get a recent outgoing message and search its text for the signature contained after the last -- found in message body. But this requires giving the script a lot more access (GmailApp can access, forward and delete existing email, unlike MailApp) and is error-prone (when text parsing fails, you might end up with an embarrassing fragment of text in your message).
Just append it directly:
var signature = "\n\n--\nFirstName LastName";
// ...
MailApp.sendEmail(... +signature, options);
(By the way, Gmail web interface and Gmail mobile app have different user signatures in general, so having another one for script-generated messages doesn't seem unusual.)

UCWA: Unable to send/Receive formatted text

I have a simple chat application working fine with plain text implemented using UCWA api in a ASP.Net MVC web application. I have to implement a formatted text next.
Referring to UCWA: integrating advanced chat options
, I go to know that, before sending the message to using ucwa.Transport.clientRequest we have to set the contentType to text/html which currently is text/plain.
So i have the function to send a message as shown below:
function sendMessage(displayName, msg, timestamp) {
var encodedMsg = encodeURIComponent(msg);
ucwa.Transport.clientRequest({
url: messagingLinks.SendMessage + "?SessionContext=" + ucwa.GeneralHelper.generateUUID(),
type: "post",
contentType: "text/html",
data: encodedMsg,
callback: function () {
addMessageToChat(displayName, encodedMsg, timestamp);
}
});
}
The implementation of handleMessage() is as shown below:
function handleMessage(data, parts) {
alert("Inside Handle message");
if (!data._embedded.message._links.plainMessage) return false;
var message = decodeMessage(data._embedded.message._links.plainMessage.href);
var decodedMsg = decodeURIComponent(message);
addMessageToChat(data._embedded.message._links.participant.title, decodedMsg, formatTime(new Date(Date.now())));
}
The problem in the above implementation is that, on the receiving end, the handleMessage() method is not entered which means i'm not receiving the incoming message.
Can anyone point me where i'm going wrong and Are the any other changes i need to do along with the above changes, so that i can send a formatted text across. A sample will be really helpful regarding the same.
Any suggestion would also be good enough. Thanks in advance.
Edit:
As suggested i have modified my makeMeAvailable method. below is the definition of the same in Authentication.js:
function makeMeAvailable() {
if (!_authenticated) {
cache.read({
id: "main"
}).done(function (cacheData) {
if (cacheData) {
var data = {
SupportedModalities: ["Messaging"],
supportedMessageFormats: ["Plain","Html"]
};
transport.clientRequest({
url: cacheData._embedded.me._links.makeMeAvailable.href,
type: "post",
data: data,
callback: handleState
});
}
});
} else {
handleState({
status: 204
});
}
}
However, the output is still the same.
The second suggestion regarding the communication API, i'm unable to locate it.
Any suggestions with this?
Here are two reasons I did not receive messages sent through UCWA API:
Charset: Default value was ISO-8859-1, I had to use UTF-8 to receive any message.
Negotiated message formats: The receiving contact only supported plain message format, but the messages were sent with text/html content type.
When it comes to the messaging formats in UCWA it should be known that by default all endpoints that support the messaging modality by default support plain messages. It is interesting to note that this limitation does not prevent sending of HTML formatted messages as you have seen in your examples.
There are two ways to enable HTML formatted messages as follows:
When issuing a request to makeMeAvailable supply an SupportedMessageFormats (array) and include Html
Issue a PUT request to communication and include Html in SupportedMessageFormats
Until either 1 or 2 has executed successfully it will be impossible to receive HTML formatted messages.

Mandrill mergetags: send email only when all merge tags are replaced

This question is related to this Check email template after meta tag replacement and before sending in Mandrill.
I would like to know if there is a way to configure the Mandrill to send an email only when all the merge tags in the email template have been replaced. Is this possible?
AFAIK this isn't possible to configure with Mandrill.
You can (maybe should) perform this using the API however - take advantage of the render method to pre-render the outgoing email, and then look for any un-replaced fields.
function has_merge_tags($string)
{
return ( strpos("|*", $string) === false AND strpos("*|", $string) === false);
}
function send_email($template_code, $merge_fields)
{
$mandrill = new Mandrill(APIKEY);
// pre-render the template with the merged fields
$result = $mandrill->templates->render($name, array(), $merge_fields);
if (has_merge_tags($result['html']))
{
// throw exception, log it, whatever
}
really_send_email($result['html']);
}
https://mandrillapp.com/api/docs/templates.php.html#method=render