When I add "METHOD: REQUEST" to iCalendar, Gmail stops recognizing as event - javascript

I'm using iCalendar to schedule events for Gmail users. However, I want to be able to send updates, if/when the event changes. I read that I must use METHOD:REQUEST in order to allow updates.
However, when I add the METHOD:REQUEST to my ics file, Gmail stops recognizing it as a calendar invite.
Here is the working example WITHOUT "METHOD:REQUEST"
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Cratic//Cratic Huddle//EN
NAME:Cratic Huddle
X-WR-CALNAME:Cratic Huddle
TIMEZONE-ID:Europe/Berlin
X-WR-TIMEZONE:Europe/Berlin
BEGIN:VEVENT
UID:60212c8395841f2cd057864f#cratic.ai
SEQUENCE:0
DTSTAMP:20210208T130601Z
DTSTART:20210219T133059Z
DTEND:20210219T140059Z
SUMMARY:Cratic Huddle
DESCRIPTION:This is the information
ORGANIZER;CN="Izzi":mailto:firstname.lastname#gmail.com
ATTENDEE;ROLE=REQ-PARTICIPANT:MAILTO:firstname.lastname#gmail.com
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER:-PT15M
DESCRIPTION:Cratic Huddle
END:VALARM
BEGIN:VALARM
ACTION:AUDIO
TRIGGER:-PT15M
ATTACH;VALUE=URI:Basso
END:VALARM
URL;VALUE=URI:cratic.ai
END:VEVENT
END:VCALENDAR
The above works perfectly; Gmail pops up with a button asking if I want to accept.
Here is the NOT working example WITH "METHOD:REQUEST"
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Cratic//Cratic Huddle//EN
METHOD:REQUEST
NAME:Cratic Huddle
X-WR-CALNAME:Cratic Huddle
TIMEZONE-ID:Europe/Berlin
X-WR-TIMEZONE:Europe/Berlin
BEGIN:VEVENT
UID:60212c8395841f2cd057864f#cratic.ai
SEQUENCE:0
DTSTAMP:20210208T125937Z
DTSTART:20210219T133059Z
DTEND:20210219T140059Z
SUMMARY:Cratic Huddle
DESCRIPTION:This is the information
ORGANIZER;CN="Izzi":mailto:firstname.lastname#gmail.com
ATTENDEE;ROLE=REQ-PARTICIPANT:MAILTO:firstname.lastname#gmail.com
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER:-PT15M
DESCRIPTION:Cratic Huddle
END:VALARM
BEGIN:VALARM
ACTION:AUDIO
TRIGGER:-PT15M
ATTACH;VALUE=URI:Basso
END:VALARM
URL;VALUE=URI:cratic.ai
END:VEVENT
END:VCALENDAR
This generates a blank email in google, with the .ics file attached. It does not appear in the calendar or anywhere else.
These two iCalendar files are identical in every other way. But for some reason adding the METHOD:REQUEST is killing the ics file / google's ability to read it.
Why??

Ok - After many hours of reading RFC5546, Stackoverflow, and many other blogs, I finally have the answers.
Scope:
Sending calendar invites to Gmail / Outlook / Privateemail (namecheap's email client)
Email clients automatically recognizing .ics files and generating "accept" templates
Events automatically appearing in client calendars as "tentative"
Sending event revisions that automatically move client calendar events
There are two fundamental principles that are critical to making this work:
The contents of the .ics file must very closely match the .ics file of the Gmail / Outlook community, this includes the parameters and the order of the parameters.
The way the .ics file is attached to the email transmission is odd but critical: (a) the .ics file must be turned into 'base64', and (b) the headers of the file need to give a type: 'text/calendar;method=REQUEST;name="file.ics"'
Below I will give examples of each, which I hope save others time on this process.
.ics Content Example:
let iCal =
`BEGIN:VCALENDAR
PRODID:-//Cratic//_Scheduler//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:REQUEST
BEGIN:VEVENT
DTSTART:${DTStart}
DTEND:${DTEnd}
DTSTAMP:${DTStamp}
ORGANIZER;CN=name:mailto:name#gmail.com
UID:${event._id}#url.com
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=name#outlook.com;X-NUM-GUESTS=0:mailto:name#outlook.com
CREATED:${DTStamp}
DESCRIPTION:${event.body}
LAST-MODIFIED:${DTStamp}
LOCATION:${location}
SEQUENCE:${sequence}
STATUS:CONFIRMED
SUMMARY:${event.title}
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR`
Please note: the above ordering is very important! And you must have no dead spaces around the text, even one extra space before or after will disrupt the email client. Also, this is a reusable dynamic iCal event template, as long as I keep a record of the event._id, I can use that _id to send revisions to all my clients.
Attaching .ics to Email Client:
// convert the invite to be base64 for attachment
const buf = Buffer.from(iCal.toString(), 'utf-8');
const base64Cal = buf.toString('base64');
// build the email
const sendEmail = async () => {
const res = await client.transmissions.send({
recipients: [{ address: 'name#outlook.com' }],
content: {
from: 'name#sparkmail.com',
subject: req.body.a.title,
text: req.body.a.body,
attachments: [
{
name: 'invite.ics',
type: 'text/calendar;method=REQUEST;name=\"invite.ics\"',
data: base64Cal,
},
],
},
options: { sandbox: false },
});
}
// send the email
sendEmail();
Please note: The attachment type is critical for Outlook to recognize the event.
Although I'm sure there are other / better ways to integrate with these services, I found the above steps allowed me to accomplish my scope.

Related

mailgun.js inline image attachments

I want to embed inline images with mailgun, however the documentation for sending attachments doesnt seem to match with the latest mailgun.js NOT mailgun-js
https://www.npmjs.com/package/mailgun.js
the mentioned docs in this readme do not exist: https://documentation.mailgun.com/api-sending.html#sending << 404's
The readme docs for this version say this:
But where do I even add an attachment? How do I set mailgun to use multipart/form-data encoding? Where/ what parameter do I use to add an attachment? There are no good type definitions either
If i have this code below, how do I just add an attachment? What's the object schema? Does it even go here? I have no clue
mg.messages.create('sandbox-123.mailgun.org', {
from: "Excited User <mailgun#sandbox-123.mailgun.org>",
to: ["test#example.com"],
subject: "Hello",
text: "Testing some Mailgun awesomness!",
html: "<h1>Testing some Mailgun awesomness!</h1>"
})
Even once set as an attachment, how do I reference it in the email to use in <img> ?
Anyone that has done with the latest mailgun.js please share your reference code. The documentation is outdated
The documentation of mailgun.js can be a bit confusing, at least for node JS, since their website refers to the old version SDK whereas their github page points to the new one. That said, their github page does offer examples for including figures in the email. There are two ways to do so
Sent as attachment files but NOT displayed in the email.
Sent as inline figure and displayed in the email.
Below shows an example (original code available here) of sending figures both as attachment and inline. Notice that for inline figures to display, one must anchor the file name with a prefix cid: in an HTML template.
To send multiple attachments or inline figures, include all files in a list (the example below uses a list of one file for both inline and attachment).
/**
Copied from https://github.com/mailgun/mailgun-js/blob/master/examples/send-email.js
*/
const fs = require('fs');
const domain = 'sandbox-123.mailgun.com';
const fromEmail = 'Excited User <mailgun#sandbox-123.mailgun.com>';
const toEmails = ['you#example.com'];
const mailgunLogo = fs.createReadStream(`${__dirname}/mailgun.png`);
const rackspaceLogo = fs.createReadStream(`${__dirname}/rackspace.png`);
mg.messages.create(domain, {
from: fromEmail,
to: toEmails,
subject: 'Hello',
html: '<img src="cid:mailgun.png" width="200px"><br><h3>Testing some Mailgun awesomness!</h3>',
text: 'Testing some Mailgun awesomness!',
inline: [mailgunLogo],
attachment: [rackspaceLogo]
})
.then((msg) => console.log(msg))
.catch((err) => console.log(err));

How to create temp files in nodejs

I want to attach an xml file and send as email. I have a string of text which I want to write in an xml file. But I don't want to actually create a file every time.
I am using nodemailer(https://community.nodemailer.com/using-attachments/) to send mail and it supports stream to attach file.
Does stream mean it has to actually create a file? Can't I just use stream somehow to send it as an attachment without creating a file.
I have xml string like this which I want to put in an xml file and send email:
const xmlStringStart = `<ENVELOPE>
<HEADER>
<TALLYREQUEST>Import Data</TALLYREQUEST>
</HEADER>
<BODY>
<IMPORTDATA>
<REQUESTDESC>
<REPORTNAME>All Masters</REPORTNAME>
<STATICVARIABLES>
<SVCURRENTCOMPANY>X</SVCURRENTCOMPANY>
</STATICVARIABLES>
</REQUESTDESC>
<REQUESTDATA>...`;
I saw PassThrough https://nodejs.org/api/stream.html#stream_class_stream_passthrough but can't figure out how to use it.
From the nodemailer document, you can use an utf-8 string as an attachment :
attachments: [ { // utf-8 string as an attachment
filename: 'text1.txt',
content: xmlStringStart // your string
},
]
I think this is simpler and better in your case. The stream option is like, reading the file as a stream then put the content to the attachment.
I would prefer it if I could have a code example to work on, but the basic concept remains the same.
You can just create a file, send it as an attachment through nodemailer, and then delete the file once that action is complete, thus making it act like a temporary file.
//create a txt file and write Hello World into it
fs.writeFileSync("/foo/bar.txt", "Hello World")
/*
Send file as attachment to nodemailer
*/
//once you're done sending file, go ahead and delete it
fs.unlink("/foo/bar.txt")
i think the filename here refers to the displayed filename as its downloaded as attachment. the path option is the file location..
as for passthrough.. it's probably like
const pt = new PassThrough();
{ // stream as an attachment
filename: 'text4.txt',
content: pt
},
then
pt.write("....");
to close: pt.end("..."()

What is the optimal way to show custom data from MSAccess DB at Wordpress site?

I need an advice from skilled Wordpress developers. My organization has internal MS Access database which contains numerous tables, reports and input forms. The structure of DB is not too complicated (persons information, events, third parties info and different relations between them). We woild like to show some portion of this info at our Wordpress site, which currently has only news section.
Because information in our DB updated each day, also we would like to make simple synchronization between MS Access DB and Wordpress (MySQL DB). Now I try to find the best way how to connect MS Access and Wordpress.
At present I see only these ways how to do this:
Make export requests and save to XML files.
Import to MySQL DB of Wordpress.
Show content on Wordpress site using Custom fields feature (or develop own plugin).
-OR-
Build own informational system on some very light PHP engine (for example CodeIgniter) on same domain as Wordpress site, which will actually show imported content.
These variants needs manual transfer info between DB each day. And I don't know possibilities of Wordpress to show custom data from DB. Would you suggest me what ways will you prefer to use in my case?
P.S. MS Access used is ver 2007+ (file .accdb). Name of fields, db's and content is on Russian language. In future we planning to add 2 new languages (English, Ukrainian). MS access DB also contains persons photos included.
---Updated info---
I was able to make semi-atomatic import/export operations using following technique:
Javascript library ACCESSdb (little bit modified for new DB format)
Internet Explorer 11 (for running ADODB ActiveX)
small VBS script for extracting attached files from MSAccess tables.
latest jQuery
Wordpress plugins for custom data (Advanced Custom Fields, Custom Post Type UI)
Wordpress Rest-API enabled (with plugins JSON Basic Authentication, ACF to REST API)
At first I've constructed data scheme at Wordpress site using custom post and custom fields technique. Then I locally run JS queries to MSAccess DB, received info I sending via jQuery to WP Rest-API endpoints. Whole transfer operation can be made with in 1 click.
But I can't upload files automatically via JS due to security limitations. This can be done in +1 click per file.
Your question is too broad.
It consist of two parts: 1. export from Access and 2. import to Wordpress. Since i'm not familiar with Wordpress I can only give you advice about 1 part. At least google shows that there is some plugins that able to import from CSV like this one:
https://ru.wordpress.org/plugins/wp-ultimate-csv-importer/
You can create a scheduled task that runs Access that runs macro that runs VBA function as described here:
Running Microsoft Access as a Scheduled Task
In that VBA function you can use ADODB.Stream object to create a UTF-8 CSV file with you data and make upload to FTP of your site.
OR
Personally i use a python script to do something similar. I prefer this way because it is more straitforward and reliable. There is my code. Notice, that i have two FTP servers: one of them is for testing only.
# -*- coding: utf-8 -*-
# 2018-10-31
# 2018-11-28
import os
import csv
from time import sleep
from ftplib import FTP_TLS
from datetime import datetime as dt
import msaccess
FTP_REAL = {'FTP_SERVER':r'your.site.com',
'FTP_USER':r'username',
'FTP_PW':r'Pa$$word'
}
FTP_WIP = {'FTP_SERVER':r'192.168.0.1',
'FTP_USER':r'just_test',
'FTP_PW':r'just_test'
}
def ftp_upload(fullpath:str, ftp_folder:str, real:bool):
''' Upload file to FTP '''
try:
if real:
ftp_set = FTP_REAL
else:
ftp_set = FTP_WIP
with FTP_TLS(ftp_set['FTP_SERVER']) as ftp:
ftp.login(user=ftp_set['FTP_USER'], passwd=ftp_set['FTP_PW'])
ftp.prot_p()
# Passive mode off otherwise there will be problem
# with another upload attempt
# my site doesn't allow active mode :(
ftp.set_pasv(ftp_set['FTP_SERVER'].find('selcdn') > 0)
ftp.cwd(ftp_folder)
i = 0
while i < 3:
sleep(i * 5)
i += 1
try:
with open(fullpath, 'br') as f:
ftp.storbinary(cmd='STOR ' + os.path.basename(fullpath),
fp=f)
except OSError as e:
if e.errno != 0:
print(f'ftp.storbinary error:\n\t{repr(e)}')
except Exception as e:
print(f'ftp.storbinary exception:\n\t{repr(e)}')
filename = os.path.basename(fullpath)
# Check if uploaded file size matches local file:
# IDK why but single ftp.size command sometimes returns None,
# run this first:
ftp.size(filename)
#input(f'overwrite it: {filename}')
ftp_size = ftp.size(os.path.basename(fullpath))
# import pdb; pdb.set_trace()
if ftp_size != None:
if ftp_size == os.stat(fullpath).st_size:
print(f'File \'{filename}\' successfully uploaded')
break
else:
print('Transfer failed')
# input('Press enter for another try...')
except OSError as e:
if e.errno != 0:
return False, repr(e)
except Exception as e:
return False, repr(e)
return True, None
def make_file(content:str):
''' Make CSV file in temp directory and return True and fullpath '''
fullpath = os.environ['tmp'] + f'\\{dt.now():%Y%m%d%H%M}.csv'
try:
with open(fullpath, 'wt', newline='', encoding='utf-8') as f:
try:
w = csv.writer(f, delimiter=';')
w.writerows(content)
except Exception as e:
return False, f'csv.writer fail:\n{repr(e)}'
except Exception as e:
return False, repr(e)
return True, fullpath
def query_upload(sql:str, real:bool, ftp_folder:str, no_del:bool=False):
''' Run query and upload to FTP '''
print(f'Real DB: {real}')
status, data = msaccess.run_query(sql, real=real, headers=False)
rec_num = len(data)
if not status:
print(f'run_query error:\n\t{data}')
return False, data
status, data = make_file(data)
if not status:
print(f'make_file error:\n\t{data}')
return False, data
fi = data
status, data = ftp_upload(fi, ftp_folder, real)
if not status:
print(f'ftp_upload error:\n\t{data}')
return False, data
print(f'Done: {rec_num} records')
if no_del: input('\n\nPress Enter to exit and delete file')
os.remove(fi)
return True, rec_num

Office.context.mailbox.displayNewMessageForm not able to attach files in outlook online clients

We are using Office.context.mailbox.displayNewMessageForm api for creating compose form in that we are adding attachments parameter with type set to file. But in this scenario, Outlook is not able to attach file in compose form of outlook online clients whereas the same scenario is working in windows Outlook 2016 and outlook for Mac.
We are referring to the example below, given in https://learn.microsoft.com/en-us/office/dev/add-ins/reference/objectmodel/preview-requirement-set/office.context.mailbox#displaynewmessageformparameters
Office.context.mailbox.displayNewMessageForm(
{
// Copy the To line from current item.
toRecipients: Office.context.mailbox.item.to,
ccRecipients: ['sam#contoso.com'],
subject: 'Outlook add-ins are cool!',
htmlBody: 'Hello <b>World</b>!<br/>',
attachments: [
{
type: 'file',
name: 'image.png',
url: 'http://contoso.com/image.png',
isInline: false
}
]
});
After using this api outlook creates new compose form with attachment (Note: I can't view or download that attachment, it is attached as label only). Refer to this image for more details
And, that attachment vanishes after some time and outlook gives an error in notification bar i.e. The following file couldn't be attached: image.png. Please try again later.Refer this image for more details
Also the same api is able to attach items in outlook online clients when attachments.type is set to item as follows:
attachments: [
{
type: 'item',
name: 'filename.png',
itemId: ewsId
}
]
Can anyone suggest why is this happening and any workaround for the above issue?

Altering Feedback.js to send info & picture to an email address

I recently stumbled upon some really cool js which renders a screenshot with a highlighted area for feedback on your website. The website for this program can be found here: http://experiments.hertzen.com/jsfeedback/
However, I'd really like to get it to send an email (to an address of my choosing) once the data is collected instead of whatever it is doing now. I've been looking through it and I'm assuming it would be done in the feedback.js file under
send: function( adapter ) {
However, I'm not entirely sure how to change what is there to keep the screenshot and data.
When you initialize Feedback(), you can set some options.
In your case the url option is important. This url should point to a php script which uses the $_POST[] data send by feedback.js.
After you got all the data you can send it in an email with php.
Here is an example how to set some options:
Feedback({
label: 'What is your problem',
header: 'Report an issue',
nextLabel: 'Next',
reviewLabel: 'Review screenshot',
sendLabel: 'Send email',
closeLabel: 'Cancel',
messageSuccess: 'Done!',
messageError: 'Oops..',
url: 'path/to/email/sendFeedback.php' // This is what you need
});
In the sendFeedback.php file you should do something like te following
if($_POST) {
$image = $_POST['data'];
$otherField = $_POST['your-other-field'];
// Send email here
}
$_POST['data'] will hold the image as a DOMString.
Other input field values are in other parameters depending on which other fields you define.
In php there are many ways to send emails.
mail() is just one of them. Info can be found at php.net..

Categories

Resources