Giter Site home page Giter Site logo

giobonvi / googlecontactseventsnotifier Goto Github PK

View Code? Open in Web Editor NEW
215.0 24.0 50.0 1.75 MB

Receive automatic email notifications before your Google Contacts birthday and other events!

License: MIT License

JavaScript 100.00%
google-calendar birthday email-notification contacts-birthday google google-script google-scripts google-birthday-notifier google-contacts email-notifications

googlecontactseventsnotifier's People

Contributors

apo-mak avatar artskydj avatar baatochan avatar cezarylaksa avatar drkrakower avatar giobonvi avatar gislinielsen avatar goggenb avatar jovanzers avatar krial057 avatar lboullo0 avatar matheusntg avatar muzavan avatar n-lefebvre avatar nadyafebi avatar peterberweiler avatar phavel avatar phg98 avatar plainerman avatar rowanthorpe avatar samizayn avatar santimar avatar skius avatar stephankn avatar supersandro2000 avatar venhance avatar vinetos avatar vladimir-kirillovskiy avatar xav83 avatar yotam180 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

googlecontactseventsnotifier's Issues

Problem with mail on date of your own birthday

Steps to reproduce

I tried test method on few dates and it worked perfectly on all them, but not on the day of my own birthday. On this day I've got 2 events - one of them is 'Happy birthday!' which Google creates automatically when you provide your birthday to Google account and the other one is my other friend birthday.

  1. Set fakedate to your own birthday
  2. run test method

Expected behavior

I guess I should get a mail with at least those friend's birthday

Current behavior

Error 'TypeError: Cannot call method "getLabel" of undefined. (line 666, file "Code")'
Line 666: var dateLabel = eachDate.getLabel();
And no mail is sent.

Context

  • Version of the script: 3.1.0

Additional things

  1. When you're using newer version than official (current official is 3.0.0), you still get note that you're using outdated version of script. (I was doing tests on latest version from new-features branch which is 3.1.0)
  2. Right now a href to newest version is set like that
    <p>(...)<a href="">You can find the latest one here</a>.</p>
    IMO it would look better if the dot was inside a href as well.

ERROR : Exceeded maximum execution time

Steps to reproduce

Maybe I set too many reminders : anticipateDays: [0, 1, 7], and I have a lot of contacts with birthdays. But I don't know for sure what is causing this.

Expected behavior

The script should not run longer than the max time allowed by google app scripts !

Current behavior

On some days when an email reminder is sent to me, it is also followed by an email from [email protected] saying basically :

Start Function Error Message Trigger End
3/16/19 10:19 AM normal Exceeded maximum execution time time-based 3/16/19 10:26 AM

Context

  version: '4.1.0',
  repoName: 'GioBonvi/GoogleContactsEventsNotifier',
  gitHubBranch: 'development' 

The script doesn't use google +, and the config code will be below.

Extended description

The exact mail from google app scripts is :


Subject : Summary of failures for Google Apps Script: Contact birthdays custom mail notifications
Your script, Contact birthdays custom mail notifications, has recently failed to finish successfully. A summary of the failure(s) is shown below. To configure the triggers for this script, or change your setting for receiving future failure notifications, click here.

Start Function Error Message Trigger End
3/16/19 10:19 AM normal Exceeded maximum execution time time-based 3/16/19 10:26 AM

Sincerely, Google Apps Script Need help? Visit the Google Apps Script documentation. Please do not reply to this message. (c) 2019 Google


Today, the email I received before the notice of failure was a notice for one contact, which had five email addresses and three phone numbers.

I don't exactly know what the problem is since I do receive a notification email for the birthdays, before I get the notification that the script took too long to run. I will leave the code of my setup below.

Possible solution

I have read somewhere that the max run time for google app scripts is 6 minutes, and the only solution is having a script run partially while keeping track of time, then stop before 6 minutes saving the current state somewhere (ex in a spreadsheet), then start again reading the last state etc...

My config code

var settings = {
  user: {
    googleEmail: '[email protected]',
    notificationEmail: '[email protected]',
    eventSource: 'CONTACTS_ONLY',
    emailSenderName: 'Contacts Events Notifications',
    lang: 'en',
    accessGooglePlus: false
  },
  notifications: {
    hour: 10,
    timeZone: 'Europe/Paris',
    anticipateDays: [0, 1, 7],
    eventTypes: {
      BIRTHDAY: true,
      ANNIVERSARY: false,
      CUSTOM: false
    },
    maxEmailsCount: -1,
    maxPhonesCount: -1,
    indentSize: 4,
    compactGrouping: true
  },
  debug: {
    log: {
      filterLevel: 'INFO',
      sendTrigger: 'ERROR'
    },
    testDate: new Date('2017/08/01 06:00:00')
  },
  developer: {
    version: '4.1.0',
    repoName: 'GioBonvi/GoogleContactsEventsNotifier',
    gitHubBranch: 'development'
  }
};

Worth adding a 'needs-triage' label?

Some repos include a needs-triage label, to acknowledge the arrival of an issue, but to say no collaborator has had time to evaluate it yet. It means you can just have this link for searching for issues to hack at, instead of this link. I'm not sure I prefer it though, because it introduces a label which is, strictly speaking, redundant - but on the other hand it is visually easier/quicker to grok...

Document/automate using GAS REST import-export in git workflow?

According to the Google documentation it is possible to sync latest commits to the scripts on Google Drive via the REST interface, so it would be nice to document that (at least for maintainer/collaborators-use) so we can avoid the whole copy-paste-update-vars tango whenever we want to test things, and users who want to do it that way can avoid the same tango whenever they want to sync an updated version from master. What would be even nicer would be to add a git-hook (which the user must copy into place if they want that, so other users don't get scared by automatic-background activity happening when they pull from github) with the following logic:

if [master-has-changed] (or if [development-has-changed] for us) {
  curl -X PUT --upload-file "{code-customized.gs,unit-tests.gs}" http://blahblahblah
}

or for that matter the hook could be a nodejs script like what they show at the nodejs google drive api quickstart - but that would require having nodejs installed (maybe it would be better for the hook to be in a more commonly-installed language like perl or python... of course using curl-invocations in a shell is probably the least dependency-heavy - for non-windows people anyway)

Get contact details (age, email, phone) of contacts without email

Moved here the message @lmatias posted in #2.

Hi GioBonvi
I have your ode running and I thanks for it.
I personalized your code with translation where you indicate.

I noticed that in the code you refer to age notification but after adding the age variable to the line
var body = bodyPrefix + bodyBuilder.join('') + bodySuffix + age;
I get the error "ReferenceError: "age" not defined. (line 157, file "Código")"

Is it possible to do what I want or not?

@lmatias Please open up a new issue instead of jumping on another one which does not concern your problem.

Script cannot access Calendar API (with default oauth key(?))

Sadly it seems that noone else had this issue before (open/closed issues)...
I cross-checked the set-up and it seems that I have a strange case with the script trying to access the Calendar (yeah it feels like deja-vu)

Steps to reproduce

What action or series of actions is the cause of the issue?

  1. followed every setup step including customization and optional settings, enabled all 3 event types (birthday, anniversary, other)
  2. set a fake date to the previous day of an anniversary which is visible in my calendar
  3. run / test

Expected behavior

Receiving a notification

Current behavior

Error: Contacts events calendar not found! Please follow the instructions (step "Enable the calendar"). (line 551, file "Code")

Context

  • Version of the script: 3.1.1
  • Checked steps :

When script in being edited : menu Resources -> Advanced Google Services
Calendar API (v3) in enabled
Going to Google API Console shows "Google Calendar API" enabled, with no activity.
Entering the Google Calendar API settings, the drop-down "all API identifiers" shows the "oauth" script URL enabled under the title "Apps Script" type "ID for Web App" with a callback URL of https://script.google.com/oauthcallback

BUT there is a banner on top of the Calendar API page that says "to use this API you need to create identifiers" and the drop-down documentation says it needs an API key...

I tried to create an API key and enable it for the Calendar API, but it doesn't seem I can have the script use it...

I tried to enable the Contacts API for a comparison, and it takes the oauth key by default (like the Calendar API) but doesn't display the "you need an API key" banner. I disabled it afterwards because it doesn't seem to be required to run the script.

Thanks for any help !!

Default notification settings getting reset?

Steps to reproduce

What action or series of actions is the cause of the issue?

  1. action 1; Set default notifications, preferably more than one for calendar events on your main calendar.
  2. action 2; Create new event and your defaults will not be there.
  3. action 3; Go back to calendar settings and confirm that default notifications have been reset.

Expected behavior

What should happen?
Defaults should not get touched by this script

Current behavior

When I had this script enabled the default notification settings get wiped when I create a new calendar event.
What happens instead?

Context

  • Version of the script: x.x.x (look for a line in the code which reads var version = 'x.x.x';);
  • Any other details which might be related to the context;

Extended description

Try to describe the problem in the most complete way you can add images,
error messages, hypothesis and observations regarding the problem here.

Possible solution

If you think you know what causes the problem or if you know a solution for it
write it here.

Some major update

To @rowanthorpe and @baatochan in particular, but also to anyone else who wants to help.

In the last few days I've been working on a way to fix the poor interaction between the various services (Google Calendar, Google Contacts, Google Plus) of this script. The main problem I wanted to solve was: we have lots of information about the various contacts out there, but, at the moment, we collect it sparsely and without a systematic approach (we are even ignoring Google Plus most of the times).

So I started with this, but one thing took to another and in the end I found myself with an almost complete rewriting of the code from the ground up...

I've pushed the commits the major-rewriting branch: I would like to hear your opinion on this new version, because I am not sure the approach I adopted is the best one and I applied for the first time some concepts I had only read about before, so there could be a lot of problems.

I've tested it and found no errors, but who knows 😉.

The test section needs to be expanded (I spent just a few minutes on that part thinking that if the code still needs to be adjusted it doesn' make sense to write the tests).

If the changes are approved before merging into master some translation updates will be required, but this is the last problem at the moment.

In the next week I won't be able to work on the code, but will gladly read and answer to any comment and question.

EDIT: for anyone who wants to test this version of the script: you will have to activate the Google+ API exactly like you did for the Google Calendar one. Just repeat the steps in the link with "Google+ API" instead of "Google Calendar API".

How to stop this

Hey I need to stop this script.. (google calender notifications)
Please help me with some screen shots.
Thank you

New release - new name: any ideas?

Hey everyone!

Now that #24 has been succesfully been closed the new release is almost ready to be deployed: as @rowanthorpe pointed out in #22, however, it could be a good idea to change the name of the project as the script does not manage just birthdays anymore.

@rowanthorpe proposed GoogleContactsEventsNotifier and I quite like it, but before proceeding I wanted to know if anyone else had any idea for a name:

Thank you again for the collaboration, everyone!

Possibility to alert for anniversaries and custom reminders?

I am hoping (but now doubting) it is possible to also include other events which the Google "Birthdays" calendar displays, like anniversaries and custom events (and indicate them as such, not as "birthdays"). In the case of custom events the name of the event-type could be retrieved and injected, too.

So far I've not found any useful documentation, and from reading the script's code and testing it against some anniversaries it seems even though the calendar displays the anniversaries, etc the API seems to only provide info about birthdays. If that turns out to be the case then this issue should be closed here and instead reported at Google. I am opening this issue anyway, in case someone knows or found something which I didn't. It would be very helpful to also get notifications for these things if it is at all possible.

install-and-setup.md correction

install-and-setup.md mentions "Google API Console" but this is now called "Google Cloud Platform API Dashboard". you also need to click the "Library" link before the "Google Calendar API" search works.

it is also unclear, to me, if I need to create credentials in the Google Calendar API as the text says "To use this API, you may need credentials. Click 'Create credentials' to get started."

TypeError: Cannot read property "preferences" from undefined.

Hello there,

First of all, let me thank you for your tremendous helpful script. I managed to get my script to run the first time successfully around 10 days ago. However, around 5 days ago I got an email notifying me about an error in the script and it has been inactive ever since. I will attach the image of the email for you to check. I hope you can help me as soon as possible.

Regards.

eslint comment causes script to re-request authorization "to publish as a webapp"

When I copied the newest development branch version of code.gs into the google script editor (and commented out the entire unit-tests.gs file), and ensured I had accessGooglePlus set to false, and tried to run notifStatus(), it asked me to authorize the script (like what happened on first-run, after activating the API). At first I thought it was the Google+ handling triggering a new request for authorization despite me having not enabled the Google+ API, but after much experimenting I saw that had nothing to do with it. It seems for some reason (maybe Google triggers a renew-auth request every X months?) it wants me to reauthorize its use of Calendar API. The problem is that, in addition to the permissions you mention in the README, it is now also asking for this:

Publish this application as a web app or a service that may share your data

which the info-box says the following for:

Convert this application into a web app or service
Share ongoing access to your account (as needed to run this service) with others on the web

I can't give any hint how to specifically reproduce this (as I had to do nothing for it to happen to me), but perhaps revoking the script's authorization, disabling the API, then re-enabling & reauthorizing may spring that request back up.

Names populated in subject but not in body text of notification email

First and foremost: thanks for this script. Really strange how Google does not offer something similar as a basic functionality out of the box for their Birthday Calendar.

I copied the script and followed the setup instructions: did the necessary configurations and activations, then executed the test case. I received the email triggered by the test case, but I noticed:

The subject of the email has:

Events: [Name 1] - [Name 2] - [Name 3] - [Name 4]

This is fine, the names match with the chosen test date + the day after.

The body text however has:

Hey! Don't forget these events:

Birthdays today ([my test date])
Birthdays tomorrow ([my test date+1])

I'd expect the names to be filled in in the body text as well?

Using version 3.1.1

bdaynotifier

Idea: list to exclude contact/eventType combos

This is just an idea which I thought I would braindump while it occurred to me. I haven't thought it through entirely, so maybe this version of the idea could turn out to be a bad idea, but on the other hand it might inspire a better variation on it...

v-- this --v

Perhaps there could be a user-editable object in the config section for skipping certain notifications, of the following form:

var settings = {
  user: {
    ...
    exceptions = { // fullName: eventType
      'My Favourite-Grandma': 'BIRTHDAY', // if she only died recently :-(
      'My Ex-Wife': ['BIRTHDAY', 'ANNIVERSARY'], // if she left you for another guy :-/
      'My Arch-Nemesis': 'CUSTOM', // if you recorded the day he got the dream-job you wanted :-|
      'Some Company': 'ANNIVERSARY', // maybe just a supplier, you couldn't care less about their anniversary
    },
    ...

The rationale being that perhaps (for the obvious reasons above, or for more subtle or context-specific reasons that I haven't thought of yet), the user may wish to keep certain dates in their Contacts for reference but does not want (annoying?, painful?) reminders of them each year.

Discuss. Feel free to flame this idea too. I can take it.

need to add some more cases for beautifyLabel function.

Steps to reproduce

What action or series of actions is the cause of the issue?

  1. run some test with test()

Expected behavior

Send email notification

Current behavior

Print Error and stopped.
Error message was similar with below.
"WORK_FAX object doesn't have replace."

Context

  • Version of the script: 3.0.0

Possible solution

I simply change "return label;" to "return String(label);" of beautifyLabel function as workaround.

Seeking help with translations for the new version of the script

Hi everyone,
in the last few days @rowanthorpe has done some incredible work on the script, essentially adding support for every type of event instead of just birthdays and I cannot wait to release this new improved version.

However the changes in the code are quite extensive and one of the parts which were interested is the translation table: some new strings have been introduced and some of the old ones have been modified, so they have to be fixed and updated before a release of the new version is possible.

The code is in the configurable-events branch: if you want to contribute you can submit a Pull Request on that branch (not on master) with the updated translation.
You'll find which strings are missing and which have to be modified directly in the code.gs file.

Example

Before (current state of the code):

'it': {
    'Age': 'Età',
    // TODO: 'Years': '',
    // TODO: 'Events': '',
    'Birthdays today': 'Compleanno oggi', // TODO: Birthday -> Birthdays (plural)
    'Birthdays tomorrow': 'Compleanno domani', // TODO: Birthday -> Birthdays (plural)
    'Birthdays in {0} days': 'Compleanno fra {0} giorni', // TODO: Birthday -> Birthdays (plural)
    // TODO: 'Anniversaries today': '',
    // TODO: 'Anniversaries tomorrow': '',
    // TODO: 'Anniversaries in {0} days': '',
    // TODO: 'Custom events today': '',
    // TODO: 'Custom events tomorrow': '',
    // TODO: 'Custom events in {0} days': '',
    'Hey! Don\'t forget these events': 'Hey! Non dimenticare questi compleanni', // TODO: birthdays -> events
    'version': 'versione',
    'by': 'by',
    'dd-MM-yyyy': 'dd-MM-yyyy',
    'Mobile phone': 'Cellulare',
    'Work phone': 'Telefono di lavoro',
    'Home phone': 'Telefono di casa',
    'Main phone': 'Telefono principale',
  },

After (fully translated code):

'it': {
    'Age': 'Età',
    'Years': 'Anni',
    'Events': 'Eventi',
    'Birthdays today': 'Compleanni oggi',
    'Birthdays tomorrow': 'Compleanni domani',
    'Birthdays in {0} days': 'Compleanni fra {0} giorni',
    'Anniversaries today': 'Anniversari oggi',
    'Anniversaries tomorrow': 'Anniversari domani',
    'Anniversaries in {0} days': 'Anniversari fra {0} giorni',
    'Custom events today': 'Eventi personalizzati oggi',
    'Custom events tomorrow': 'Eventi personalizzati domani',
    'Custom events in {0} days': 'Eventi personalizzati fra {0} giorni',
    'Hey! Don\'t forget these events': 'Hey! Non dimenticare questi eventi',
    'version': 'versione',
    'by': 'by',
    'dd-MM-yyyy': 'dd-MM-yyyy',
    'Mobile phone': 'Cellulare',
    'Work phone': 'Telefono di lavoro',
    'Home phone': 'Telefono di casa',
    'Main phone': 'Telefono principale',
  },

To @lboullo0, @muzavan, @DrKrakower, @cezarylaksa in particular: I want to seize the opportunity to thank you once more for your past contributions; I would be extremely grateful if you could help with this again, but feel no obligation whatsoever 😃

Birthday notifications., im not able to find calender id.,?

hi team.,
in birthday notifications script.,
im not able to find my calender id.,
please help me with some screenshot.,
Thanks in advance.,
and im not programming geek.,
and i changed some variables., only my mail id only.,
and where to change variables.,
please help me.,
Thanks in advance.,

reminder eMail is not using photos from Google Contacts

Steps to reproduce

Set a proper test date to match a contact having a photo in Google Contacts and run test

Expected behavior

email should contain the photo from contacts.

Current behavior

email uses default profile image as contact in question has probably no public photo.

Context

  • Version of the script: 5.0.0

Possible solution

I suggest to read the photo from contacts. API is at https://developers.google.com/contacts/v3#retrieving_a_contacts_photo

I debugged a bit. Reading photo seems possible, but I do not fully understand what data sources get merged to have the current photo URL.

Google Cloud Platform API Dashboard link not found

Actions taken

I followed the instructions until I got to the step "Once you have done this open Resources->Advanced Google services again and click on the link which says "Google Cloud Platform API Dashboard".

Expected behavior

A dialog box appeared, but I found no link labeled Google Cloud Platform API Dashboard. Therefore, no further progress made.

Possible solution

I have no idea.

v4.0.0 is ready for release - except for translations

Paging all the translators: @rowanthorpe, @lboullo0, @muzavan, @DrKrakower, @cezarylaksa,m @baatochan, @jayforce, @biboxay321, @88scythe.

Version 4.0.0 is almost ready for release: the last step, as usual, is to update all the translations: if any of you guys want to contribute with this you are, as always, warmly welcome!

You can find the branch here : please make sure to base your PRs against the v4.0.0 branch and not against master or development.

EDIT: v4.0.0 has been released. If anyone wants to contribute with the german and/or indonesian translation please base your PR on master.

Thank you!

PS: as always, if you have any question about the translation you can freely ask here.

Calendar ID

@rowanthorpe @baatochan

I am trying to implement what we discuessd in #87 and got stuck into a decision loop which I need some help to exit from.

  1. I've done some tests and have verified that the calendarId setting overwrites whichever setting you have chosen in the Google Calendar setting page (e.g. if your birthday calendar has "Contacts only" but you use addressbook#... in the script you will actually receive notifications about your google plus contacts)
  2. We know only two valid calendar IDs: #[email protected] and addressbook#[email protected]
  3. We want to make it as easy as possible for the user to configure the script
  4. So we could make the user insert a calendar ID and introduce a check on it, however
  5. If we simply check for @group.v.calendar.google.com it will match the holyday calendar as well (and possibly other calendars I am not aware of)
  6. If we strictly check the calendar ID against the two known valid calendars we are assuming that they are the only two valid ones
  7. Having made this assumption, wouldn't it make more sense to simply give the user a setting to choose "contacts only/contacts+gplus" and then we build the correct ID by ourselves in the script (thus granting it to be correct)?

If it was for me I would do this:

  • I'd replace calendarId with eventSource, which has these valid values: '', 'CONTACTS_ONLY', 'CONTACTS_AND_GPLUS'. The default value would be ''
  • eventSource is empty -> the script defaults to the value set in Google Calendar.
    The list of the calendars is retrieved and it will contain one of #[email protected] and addressbook#[email protected]. Whichever one is in the list will be used (this would be the "heuristic" method).
  • eventSource is 'CONTACTS_ONLY' or 'CONTACTS_AND_GPLUS': the correct id is built and used by the script

But I'd like to hear your opinion on this.

Problem with accessing g+ data

The line 251 right now looks like that: if (this.gplusProfileId === null && eventData['goo.contactsProfileId']) { .

However everytime it's run this.gplusProfileId is undefined in my case, not null and the line 252 is not called this.getInfoFromGPlus(eventData['goo.contactsProfileId']);.

I've done a quick workaround for it in 45aca7b, but I know it has to be done differently.

I have also question about G+ API. Is there info about activating it in the instruction of setting up the script? I didn't know I have to manually turn it on :/

Translations

Hi everyone: I'm opening this issue especially because of Hacktoberfest, a DigitalOceans's initiative which is a great way to introduce coders from all over the world to contributing to open source projects.

This script has some translations included in the source code, but at the moment the German and Indonesian ones are incomplete (some strings need translations, while others have already been translated): if you know any of these two languages and want to help us by completing the translations please do so! You could obviuosly add any other laguage as well.

This is a comprehensive guide on how to add or edit a translation, but please: feel free to ask for help in this thread if you need anything.

Age displays as "-1871" in email if contact has year of birth

Steps to reproduce

What action or series of actions is the cause of the issue?

  1. Get a reminder for a birthday including the year, e.g. "8. April 1991"
  2. see age as "-1871" in email

Expected behavior

I expect the real age to be displayed in the email.

Current behavior

I see age as "-1871", which obviously is wrong.

Context

Google Contacts Events Notifier (Version 5.0.1)

Birthday of the contact for testing purposes: 8. April 1991.

Extended description

not applicable.

"ReferenceError: "Calendar" is not defined. (line 307, file "Code")"

Hey,

first of all thank you very much for finding a solution to a problem that has been nagging me for months now. I was extremly happy when I found your script, alas, I can't get it to work.

I followed your instructions from here to the letter, but unfortunately received the following mail a couple of hours later:
image

Don't really know what to do with this and could use some help. In my file, the lines around line 307 are as follows:
image

In case you need any more information, please let me know. Thank you!

Possible chance to simplify the script and let Google do the heavy lifting (data merging)

I noticed in the docs for the latest (3.0) API for Contacts at the top there is the following note:

Note: For read and write access to users' contacts, use the People API, which provides
both contact and profile information using JSON instead of the older GData protocol.

which links to the People API, which seems to be a merged datasource for contact info and profile data from various sources (I'm guessing primarily Google+). I haven't dived deeply into it (I am not registered for anything other than Contacts, and am hesitant to start registering for other things just to test this API). It would be nice if someone who already has access to Google+ etc wants to test whether this API is relevant and adds any value, or is just a red-herring...

Time zone issue

Steps to reproduce

What action or series of actions is the cause of the issue?

  1. I live in NewZealand, many of my friends are in Europe which is why I want to be reminded one day prior at 5 pm and on their birthday on 5 pm;
  2. action 2;
  3. action 3;

Expected behavior

What should happen?

Lets say Birthday is 5. Oct. so I should get a notification on 4. Oct at 5pm NZ time and on 5. Oct 5pm NZ time

Current behavior

What happens instead?

I get a notification on 3. Oct and on 4. Oct. The birthday is shown to me to be on 4. Oct instead of 5. Oct.

Context

  • Version of the script: 2.1.3
  • Any other details which might be related to the context;

Extended description

Try to describe the problem in the most complete way you can add images,
error messages, hypothesis and observations regarding the problem here.

Possible solution

There is probably an error in the calculation between time zones.

Not working

Hi:

I check your code and granted all permissions. Didn't received any notification.

Any clue?

Thanks

Notification subject and text are not coherent

When notification.eventTypes is set to ignore a certain type of event (e.g. ANNNIVERSARY) and a user has an ANNIVERSARY event on a certain day the notificiation for that day will not contain the event in teh text, but will contain the name of the contact in the subject.

There are some other cases where similar problems happen related to teh new "blacklisting" option.

I wrote a patch which fixes this, I'llopen a PR once I've tested it some more. I'm leaving this here so that if anyone else notices this problem noone wastes time working on a fix which already exists.

change var myMail to a non used address

I updated the script yesterday and did not change the mail in line 26 in code.gs. Luckily a friend has his birthday tomorrow and I got a mail today that the servre did not accept the mail. I thought whut? Is @somemail.com actually a mail addres? If you wisit somemail.com it ridirects you to a login screen. I would suggest to change that mail addres to something that does not actualk exist to minimize stress on that server if someone does not change that mail adress by accident.

Add `verbose` settings-var (default=false) to display all labels (non-grouped)?

Maybe some users will prefer having all label-types listed in their notifications (e.g. Work fax: w, Main phone: x - y, Garden shed morse-code device: z - instead of all being under Other phone: w - x - y - z), so we could add a verbose (or similar) variable to the settings (default to false) which doesn't group number/email labels into "other" at all, but still groups the numbers/emails within each label. Most of that functionality can be reinstated from previous commits which removed it when in favour of "other", but wrapped in a conditional. Just an idea, so if you disagree feel free to close this.

Mandatory customization

This is a brilliant idea and I'd like to use this script.

Sorry to bother you but I simply do not fully understand the instructions.
What am I supposed to do with the "Mandatory customization"?
It says "variables that you must initialize correctly" but I do not understand what that means. What exactly should I do?
https://github.com/GioBonvi/GoogleContactsEventsNotifier/blob/master/docs/install-and-setup.md#mandatory-customization

Steps to reproduce

What action or series of actions is the cause of the issue?

  1. action 1;
  2. action 2;
  3. action 3;

Expected behavior

What should happen?

Current behavior

What happens instead?

Context

  • Version of the script: x.x.x - look for a line near the top of the code which
    reads:
    version: 'w.x.y-z',
  • Any other details which might be related to the context;

Extended description

Try to describe the problem in the most complete way. You can add images,
error messages, hypothesis and observations regarding the problem here.

Possible solution

If you think you know what causes the problem or if you know a solution for it
write it here.

I am not receiving any email

Steps to reproduce

What action or series of actions is the cause of the issue?

  1. Followed all instructions and I'm not receiving an error but no emails either.
  2. Also tried to run the test function with a custom date but don't get an email
  3. My timezone is Pacific/Auckland
  4. the calendar id is: addressbook#[email protected]
  5. I also tried another notificationEmail that is different from my gmail.

Expected behavior

What should happen?

I receive an email.

Current behavior

What happens instead?

No email no error.

Context

  • Version of the script: 4.0.0

Extended description

  • I can see that a call to the calendar is made.
  • I can see the granted OAuth scopes
  • I can see the executions notifStart runs approx 0.5s and test 2s

maxEmailsCount setting does not filter all email addresses

A user who did not want to register on GitHub just to report a single issue sent me this bug report via email:

When maxEmailsCount: 0
still the "other email" is appended to the name. I quess same happens to
the "other" phone numbers.

I have identified the issue: the script actually "counts" the email addresses only while extracting them from a Google Contact. This means that the email in the "raw event" (which is classified as OTHER_EMAIL) is not included in the count and is therefore displayed even when maxEmailsCount is set to 0.

I'm already working on a quick fix for this moving the "email counting and filtering" process from the data collection phase to the getLines() function, so that all the email addresses are collected, but only some are displayed, as it should be.

Google+ is being shut down

Google has recently announced that "Google+ for consumers" is going to close (complete shutdown is scheduled for August 2019) following some security problems and given the extremely low usage of the platform (This Google Blog post has some more details).

This almost certainly means that we'll have to remove Google+ integration from the script, possibly even before August 2019 as a complete shutdown of the service might cause unexpected and unhandled errors which could potentially break the script for some users.

August 2019 is quite far in the future at the moment, but I think we should keep this in mind. In the meantime let's wait for more details like API deprecations dates.

Another update in the translation strings

To @lboullo0, @muzavan, @DrKrakower, @cezarylaksa, @baatochan, @rowanthorpe and anyone else who wants to help with the translations.

I have just pushed some commits introducing two new features (default profile images and notifications for outdated scripts) and the latter introduced tow new strings in the translation table which have to be updated.

The code can be found in the new-features branch: if you want to contribute you can submit a Pull Request on that branch (not on master) with the updated translation.
You'll find which strings are missing and which have to be modified directly in the code.gs file.

Example

Before (current state of the code):

'it': {
    'Age': 'Età',
    'Years': 'Anni',
    'Events': 'Eventi',
    'Birthdays today': 'Compleanni oggi',
    'Birthdays tomorrow': 'Compleanni domani',
    'Birthdays in {0} days': 'Compleanni fra {0} giorni',
    'Anniversaries today': 'Anniversari oggi',
    'Anniversaries tomorrow': 'Anniversari domani',
    'Anniversaries in {0} days': 'Anniversari fra {0} giorni',
    'Custom events today': 'Eventi personalizzati oggi',
    'Custom events tomorrow': 'Eventi personalizzati domani',
    'Custom events in {0} days': 'Eventi personalizzati fra {0} giorni',
    'Hey! Don\'t forget these events': 'Hey! Non dimenticare questi eventi',
    'version': 'versione',
    'by': 'by',
    'dd-MM-yyyy': 'dd-MM-yyyy',
    'Mobile phone': 'Cellulare',
    'Work phone': 'Telefono di lavoro',
    'Home phone': 'Telefono di casa',
    'Main phone': 'Telefono principale',
    // TODO: 'It looks like you are using an outdated version of this script': '',
    // TODO: 'You can find the latest one here': '',
}

After (fully translated code):

'it': {
    'Age': 'Età',
    'Years': 'Anni',
    'Events': 'Eventi',
    'Birthdays today': 'Compleanni oggi',
    'Birthdays tomorrow': 'Compleanni domani',
    'Birthdays in {0} days': 'Compleanni fra {0} giorni',
    'Anniversaries today': 'Anniversari oggi',
    'Anniversaries tomorrow': 'Anniversari domani',
    'Anniversaries in {0} days': 'Anniversari fra {0} giorni',
    'Custom events today': 'Eventi personalizzati oggi',
    'Custom events tomorrow': 'Eventi personalizzati domani',
    'Custom events in {0} days': 'Eventi personalizzati fra {0} giorni',
    'Hey! Don\'t forget these events': 'Hey! Non dimenticare questi eventi',
    'version': 'versione',
    'by': 'by',
    'dd-MM-yyyy': 'dd-MM-yyyy',
    'Mobile phone': 'Cellulare',
    'Work phone': 'Telefono di lavoro',
    'Home phone': 'Telefono di casa',
    'Main phone': 'Telefono principale',
    'It looks like you are using an outdated version of this script': 'Sembra che tu stia usando una vecchia versione di questo script.',
    'You can find the latest one here': 'Puoi trovare l\'ultima qui',
}

As you can probably see the whole sentence is 'It looks like you are using an outdated version of this script. You can find the latest one here', but it was spliced into two because:

  1. a translation of 'here' could probably turn out useful in the future
  2. some HTML code had to be inserted in between

Thanks to everyone and sorry for bothering you: feel absolutely free to contribute or not to; I am paging you because you've all been so nice and available in the past 😉.

Logo restyle

I think the current logo could really benefit from a redesign: if anyone wants to give it a try please do so! It's not necessary to open a PR for every proposal, just link the image in an answer to this issue.

Problems which should be solved:

  • currently it's nothing more than a patchwork of icons with conflicting styles and colors
  • it uses Google Contact and Google Calendar icons: I am not sure what copyright laws apply to icons and service logos or if this falls under "fair use". Maybe someone knwoledgeable in this area could shed light on this; in the meantime not using them is probably the best way to go
  • it's a raster image: as pointed out in #129 it would be great to have it as a vector image

Guidelines:

  • if you do not know what this script does you can give a quick read to the homepage.
    Alternatively this is a TL;DR: GoogleContactsEventsNotifier is a script built on the Google Script platform which lets you receive notifications for your contacts' events (birthdays, anniversaries and custom events). It collects data from your event Calendar, from your Contacts and from Google+ profiles to build a customized email notification which sums up upcoming birthdays and events.
  • feel free to completely change the structure, dimensions, format and style of the logo: when I put it together I wanted to convey the idea of a service that uses Calendar, Contacts and Gmail to get you those notifications, however I'd love to see any alternative ideas
  • a little note regarding Google+: I did not include it in the logo because at the time it was not integrated in the script nor did I plan to integrate it. However, as explained in #131, Google+ is going to close in the next 10 months, so I'd say including it in the new logo is not worth it anyway even if you want to keep the "service aggregation" theme

Thank you in advance to anyone who wants to give a shot at this!

Birthday notification email stopped working

Before reporting a new issue please double check that:

If this issue is not about a bug or a problem you can delete all of this and write whatever you want.


Script stopped working a month ago. I receive an email from Google with this message:

Inicio Función Mensaje de error Activación Fin
20/07/17 10:14 checkBirthdays TypeError: No se puede encontrar la función getTime en el objeto [object Object]. (línea 339, archivo "birthday-notifications") time-based 20/07/17 10:14

Steps to reproduce

What action or series of actions is the cause of the issue?

  1. Copy your script into google script console
  2. Follow instructions to edit my own values (email, calendar-id)
  3. wait for one day

Expected behavior

The email with birthdays of the day IS sent

Current behavior

The email with birthdays of the day is NOT sent, and error email from Google is sent instead

Context

  • Version of the script: 2.1.3;
  • I was using previous version of the script, and although it worked, it stopped working a month ago (no changes in the script), that's why I decided to upgrade to 2.1.3 expecting it fixed the error. But it didn't.

Possible solution

?

Configuration helper

I have had this idea some time ago, I have tried fixing some rough edges, but there is still something to work out.

My idea would be to deploy a google script (as a web app) which the iser could use to configure GCEN.

This is a rough draft of the concept:

  • a web page with a form field (text, list, check box...) for each setting
  • the user fills in the settings, receiving immediate feedback about malformed/invalid input
  • the user submits the settings
  • a more thorough check is performed on the input
  • if everything is alright the user is presented with the code correctly configured which can be copied and deployed as usual

This would mean:

  • users would be helped in the configuration of the script (and issues about misconfigurations should happen less often)
  • we would need to maintain this second script as well (although it should be easier as users would not access it directly and its logic would be simpler)
  • we could split the monolythic code.gs into smaller, more manageable files

Google Contacts Custom Fields

Hi guys,

Just wondering what/where I have to insert in order to add a line of info in the notification emails that would be pulled from a custom field in Google Contacts?

Bit of context: I'm setting up notifications for staff anniversaries and we give out a bottle of Red/White/Beers/Rose - I'd like to add a custom field in Google Contacts that specifies this, and for the email notification to show it as well.

Thanks in advance!
S

ReferenceError

Hi, I copied your code but got this error when i Ran the script "checkBirthdays"
ReferenceError: "Calendar" is not defined. (line 237, file "Code")
the line is:
birthdays = Calendar.Events.list(calendarId, optionalArgs).items;

I also received an email about the error.

FYI, I deleted all the languages you had in there (didn't think it was necessary for it to be in there for me) but don't think this caused the issue? This is how the language section looks like in my code:

var i18n = {
  // For all languages, if a translation is not present the untranslated string
  // is returned, so just leave out translations which are the same as the English.

  // An entry for 'en' marks it as a valid lang config-option, but leave it empty
  // to just return unaltered phrases.
  'en': {},    
  /* To add a language:
  '[lang-code]': {
    '[first phrase]': '[translation here]',
    '[second phrase]': '[translation here]',
    ...
  }
  */
};

Error : Bad value (line 497, file "Code")

I had done all the settings as you described at Link. But at the end, when i click on the menu Run->start it displays an error that "Bad value (line 497, file "Code")". Google Scriprt which I used is posted herein below,

/* global Logger CalendarApp ScriptApp ContactsApp Utilities Calendar UrlFetchApp MailApp */

/*
 * Thanks to this script you are going to receive an email before the birthday of each of your contacts.
 * The script is easily customizable via some variables listed below.
 */

// START MANDATORY CUSTOMIZATION

// You need to personalize these values, otherwise the script won't work.

/*
 * GOOGLE EMAIL ADDRESS
 *
 * First of all specify the gmail address of your Google Account.
 * This is needed to retrieve informations about your contacts.
 */
var myGoogleEmail = REDACTED;

/*
 * NOTIFICATION EMAIL ADDRESS
 *
 * Now specify to which email address the notifications should be sent.
 * This can be the same email address of the previous line or any other email address.
 */
var myEmail = REDACTED;

/*
 * ID OF THE BIRTHDAY CALENDAR
 *
 * Open up https://calendar.google.com, in the menu on the left click on the arrow next to the birthday calendar
 * and choose 'Calendar settings', finally look for a the "Calendar ID field" (it should be something similar to
 * #[email protected]): copy and paste it between the quotes in the next line.
 */
var calendarId = REDACTED;

/*
 * YOUR TIMEZIONE
 *
 * If you need to adjust the timezone of the email notifications use this variable.
 *
 * Accepted values:
 *  GMT/UTC - examples: 'UTC+2' 'GMT-4'
 *  regional timezones: 'Europe/Berlin' (See here for a complete list: http://joda-time.sourceforge.net/timezones.html)
 */
var myTimeZone = 'UTC+05:30';

/*
 * HOUR OF THE NOTIFICATION
 *
 * Specify at which hour of the day would you like to receive the email notifications.
 * This must be a number between 0 and 23.
 */
var notificationHour = 9;

/*
 * HOW MANY DAYS BEFORE BIRTHDAY
 *
 * Here you have to decide when you want to receive the email notification.
 * Insert between the square brackets a comma-separated list of numbers, where each number
 * represents how many day before a birthday you want to be notified.
 * If you want to be notified only once then enter a single number between the brackets.
 *
 * Examples:
 *  [0] means "Notify me the day of the birthday";
 *  [0, 7] means "Notify me the day of the birthday and 7 days before";
 *  [0, 1, 7] means "Notify me the day of the birthday, the day before and 7 days before";
 *
 * Note: in any case you will receive one email per day: all the notifications will be grouped
 * together in that email.
 */
var anticipateDays = [0];

/*
 * LANGUAGE
 *
 * For internationalization (translation) enter the two-digit lang-code here (to add your language just fill in the
 * 'i18n' hash below and change lang here to match that).
 */
var lang = 'en';

// For places where an indent is used for display reasons (in plaintext email), this number of spaces is used.
var indentSize = 2;

// END MANDATORY CUSTOMIZATION

// START DEBUGGING OPTIONS

// When debugging is not wanted you can set this true to disable debugging calls, for a slight speedup.
var noLog = false;

// When debugging (noLog == false) and you want the logs emailed too, set this to true.
var sendLog = false;

/*
 * The test() function can be run on a specified date as if it is "today". Specify that date here in the format
 * YEAR/MONTH/DAY HOUR:MINUTE:SECOND
 * Choose a date you know should trigger a birthday notification.
 */
var fakeTestDate = '2017/02/14 06:00:00';

// END DEBUGGING OPTIONS

/*
 * There is no need to edit anything below this line.
 * The script will work if you inserted valid values up until here, however feel free to take a peek at my code ;)
 */

var version = '2.1';

// Merge an array at the end of an existing array.
if (typeof Array.prototype.extend === 'undefined') {
  Array.prototype.extend = function (array) {
    var i;

    for (i = 0; i < array.length; ++i) {
      this.push(array[i]);
    }
    return this;
  };
}


if (typeof String.prototype.format === 'undefined') {
  String.prototype.format = function () {
    var args;

    args = arguments;
    return this.replace(/\{(\d+)\}/g, function (match, number) {
      return typeof args[number] !== 'undefined'
        ? args[number]
        : match
      ;
    });
  };
}

var indent = Array(indentSize + 1).join(' ');

var i18n = {
  // For all languages, if a translation is not present the untranslated string
  // is returned, so just leave out translations which are the same as the English.

  // An entry for 'en' marks it as a valid lang config-option, but leave it empty
  // to just return unaltered phrases.
  'en': {},
  'el': {
    'UNKNOWN': 'ΑΓΝΩΣΤΟ',
    'Age': 'Ηλικία',
    'Birthday': 'Γενέθλια',
    'Birthday today': 'Γενέθλια σήμερα',
    'Birthday tomorrow': 'Γενέθλια αύριο',
    'Birthday in {0} days': 'Γενέθλια σε {0} ημέρες',
    'Hey! Don\'t forget these birthdays': 'Μην ξεχάσετε αυτά τα γενέθλια',
    'Google Calendar Contacts Birthday Notification': 'Ενημερώσεις Γενεθλίων του Ημερολογίου Google',
    'version': 'εκδοχή',
    'by': 'από τον', // τον=masculine,την=feminine (using the masculine, in one place, for now but may need more context in future)
    'dd-MM-yyyy': 'dd-MM-yyyy',
    'send email now': 'στείλτε email τώρα',
    'Mobile phone': 'Κινητό',
    'Work phone': 'Τηλέφωνο εργασίας',
    'Home phone': 'Τηλέφωνο οικίας',
    'Main phone': 'Κύριο τηλέφωνο',
  },
  'it': {
    'UNKNOWN': 'SCONOSCIUTO',
    'Age': 'Età',
    'Birthday': 'Compleanno',
    'Birthday today': 'Compleanno oggi',
    'Birthday tomorrow': 'Compleanno domani',
    'Birthday in {0} days': 'Compleanno fra {0} giorni',
    'Hey! Don\'t forget these birthdays': 'Hey! Non dimenticare questi compleanni',
    'version': 'versione',
    'by': 'by',
    'dd-MM-yyyy': 'dd-MM-yyyy',
    'send email now': 'invia email ora',
    'Mobile phone': 'Cellulare',
    'Work phone': 'Telefono di lavoro',
    'Home phone': 'Telefono di casa',
    'Main phone': 'Telefono principale',
  },
  /* To add a language:
  '[lang-code]': {
    '[first phrase]': '[translation here]',
    '[second phrase]': '[translation here]',
    ...
  }
  */
};

var birthdayCalendar = CalendarApp.getCalendarById(calendarId);
var calendarTimeZone = birthdayCalendar ? birthdayCalendar.getTimeZone() : null;
var inlineImages;

// Replace a Field.Label object with its "beautified" text representation.
function beautifyLabel (label) {
  switch (label) {
    case ContactsApp.Field.MOBILE_PHONE:
      return _('Mobile phone');
    case ContactsApp.Field.WORK_PHONE:
      return _('Work phone');
    case ContactsApp.Field.HOME_PHONE:
      return _('Home phone');
    case ContactsApp.Field.MAIN_PHONE:
      return _('Main phone');
    default:
      return label;
  }
}

/*
 * Get the translation of a string.
 * If the language or the chosen string is invalid return the string itself.
 */
function _ (string) {
  return i18n[lang][string] || string;
}

function doLog (arg) {
  noLog || Logger.log(arg);
}

/*
 * Look for birthdays on a certain date.
 * If testDate is not specified Date.now() will be used.
 */
function checkBirthdays (testDate) {
  var anticipate, subjectPrefix, subjectBuilder,
    bodyPrefix, bodySuffix1, bodySuffix2, bodyBuilder, htmlBodyBuilder, now, subject, body, htmlBody;

  doLog('Starting run of GoogleCalendarBirthdayNotifications version ' + version + '.');
  // The script needs this value in milliseconds, but the user entered it in days.
  anticipate = anticipateDays.map(function (n) { return 1000 * 60 * 60 * 24 * n; });
  // Verify that the birthday calendar exists.
  if (!birthdayCalendar) {
    doLog('Error: Birthday calendar not found!');
    doLog('Please follow the instructions at this page to activate it: https://support.google.com/calendar/answer/6084659?hl=en');
    return;
  }

  // Start building the email notification text.
  subjectPrefix = _('Birthday') + ': ';
  subjectBuilder = [];
  bodyPrefix = _('Hey! Don\'t forget these birthdays') + ':';
  bodySuffix1 = _('Google Calendar Contacts Birthday Notification') + ' (' + _('version') + ' ' + version + ')';
  bodySuffix2 = _('by ') + 'Giorgio Bonvicini';
  // The email is built both with plain text and HTML text.
  bodyBuilder = [];
  htmlBodyBuilder = [];

  // Use the testDate if specified, otherwise use todays' date.
  now = testDate || new Date();
  doLog('Date used: ' + now);

  inlineImages = {};
  /*
   * Look for birthdays on each of the days specified by the user.
   * timeInterval represents how many milliseconds in the future to check.
   */
  anticipate.forEach(
    function (timeInterval) {
      var optionalArgs, birthdays, formattedDate, whenIsIt;

      // Set the search filter to include only events happening 'timeInterval' milliseconds after now.
      optionalArgs = {
        // Filter only events happening between 'now + timeInterval'...
        timeMin: Utilities.formatDate(new Date(now.getTime() + timeInterval), calendarTimeZone, 'yyyy-MM-dd\'T\'HH:mm:ss\'Z\''),
        // ... and 'now + timeInterval + 1 sec'.
        timeMax: Utilities.formatDate(new Date(now.getTime() + timeInterval + 1000), calendarTimeZone, 'yyyy-MM-dd\'T\'HH:mm:ss\'Z\''),
        // Treat recurring (like birthdays) events as single events.
        singleEvents: true
      };
      doLog('Checking birthdays from ' + optionalArgs.timeMin + ' to ' + optionalArgs.timeMax);

      // Get all the matching events.
      birthdays = Calendar.Events.list(calendarId, optionalArgs).items;
      doLog('Found ' + birthdays.length + ' birthdays in this time range.');
      // If no event is found for this particular timeInterval skip it.
      if (birthdays.length < 1) {
        return;
      }

      formattedDate = Utilities.formatDate(new Date(now.getTime() + timeInterval), calendarTimeZone, _('dd-MM-yyyy'));
      // Build the headers of birthday grouping by date.
      bodyBuilder.push(' * ');
      htmlBodyBuilder.push('<dt style="margin-left:0.8em;font-style:italic">');
      switch (timeInterval / (24 * 60 * 60 * 1000)) {
        case 0:
          whenIsIt = _('Birthday today') + ' (' + formattedDate + ')';
          break;
        case 1:
          whenIsIt = _('Birthday tomorrow') + ' (' + formattedDate + ')';
          break;
        default:
          whenIsIt = _('Birthday in {0} days').format(timeInterval / (24 * 60 * 60 * 1000)) + ' (' + formattedDate + ')';
      }
      bodyBuilder.push(whenIsIt, ':\n');
      htmlBodyBuilder.push(whenIsIt, '</dt><dd style="margin-left:0.4em;padding-left:0"><ul style="list-style:none;margin-left:0;padding-left:0;">');

      // Add each of the birthdays for this timeInterval.
      birthdays.forEach(
        function (event, i) {
          var contact;

          doLog('Contact #' + i);
          contact = new Contact(event);
          subjectBuilder.push(contact.fullName);
          bodyBuilder.extend(contact.getPlainTextLine());
          htmlBodyBuilder.extend(contact.getHtmlLine());
        }
      );

      bodyBuilder.push('\n');
      htmlBodyBuilder.push('</ul></dd>');
    }
  );

  // If there is an email to send...
  if (bodyBuilder.length > 0) {
    subject = subjectPrefix + subjectBuilder.join(' - ');
    body = [bodyPrefix, '\n\n']
           .concat(bodyBuilder)
           .concat(['\n\n', indent, bodySuffix1, '\n', indent, bodySuffix2, '\n'])
           .join('');
    htmlBody = ['<h3>', bodyPrefix, '</h3><dl>']
               .concat(htmlBodyBuilder)
               .concat(['</dl><hr/><p style="text-align:center;font-size:smaller"><a href="https://github.com/GioBonvi/GoogleCalendarBirthdayNotifications">', bodySuffix1, '</a><br/>', bodySuffix2, '</p>'])
               .join('');

    // ...send the email notification.
    doLog('Sending email...');
    MailApp.sendEmail({
      to: myEmail,
      subject: subject,
      body: body,
      htmlBody: htmlBody,
      inlineImages: inlineImages
    });
    doLog('Email sent.');
  }
  // Send the log if the debug options say so.
  if (!noLog && sendLog) {
    MailApp.sendEmail({
      to: myEmail,
      subject: 'Logs for birthday-notification run',
      body: Logger.getLog()
    });
  }
}

/*
 * Extract contact data from a birthday event and integrate it with additional data
 * recovered directly from Google Contact through the contactId field if present.
 */
var Contact = function (event) {
  var eventData, googleContact, currentYear, birthdayYear, phoneFields;

  // Extract basic data from the event description.
  eventData = event.gadget.preferences;
  this.id = (typeof eventData['goo.contactsContactId'] === 'undefined') ? '' : eventData['goo.contactsContactId'];
  this.fullName = (typeof eventData['goo.contactsFullName'] === 'undefined') ? '' : eventData['goo.contactsFullName'];
  this.email = (typeof eventData['goo.contactsEmail'] === 'undefined') ? '' : eventData['goo.contactsEmail'];
  this.photo = (typeof eventData['goo.contactsPhotoUrl'] === 'undefined') ? '' : eventData['goo.contactsPhotoUrl'];
  this.age = '';
  this.phoneFields = [];
  if (this.email !== '') {
    doLog('Has email.');
  }
  if (this.fullName !== '') {
    doLog('Has full name');
  }
  if (this.photo !== '') {
    doLog('Has photo.');
  }

  // If the contact has a contactId field try to get the Google Contact corresponding to that contactId.
  if (this.id !== '') {
    googleContact = ContactsApp.getContactById('http://www.google.com/m8/feeds/contacts/' + encodeURIComponent(myGoogleEmail) + '/base/' + this.id);
  }

  // If a valid Google Contact exists extract some additional data.
  if (googleContact) {
    // Extract contact's age if the contact has the birthday year.
    if (googleContact.getDates(ContactsApp.Field.BIRTHDAY)[0]) {
      doLog('Has birthday year.');
      currentYear = Utilities.formatDate(new Date(event.start.date.replace(/-/g, '/')), calendarTimeZone, 'yyyy');
      birthdayYear = googleContact.getDates(ContactsApp.Field.BIRTHDAY)[0].getYear();
      this.age = birthdayYear !== '' ? (currentYear - birthdayYear).toFixed(0) : '';
    }
    // Extract contact's phone numbers.
    phoneFields = googleContact.getPhones();
    if (phoneFields.length > 0) {
      this.phoneFields = phoneFields;
      doLog('Has phones.');
    }
  }

  /*
   * Use the extracted data to build a plain line of text displaying all the
   * collected data about the contact.
   */
  this.getPlainTextLine = function () {
    var line;

    line = [];
    // Full name.
    line.push('\n', indent, this.fullName);
    // Age.
    if (this.age !== '') {
      line.push(' - ', _('Age'), ': ', this.age);
    }
    if (this.email !== '' || typeof this.phoneFields !== 'undefined') {
      line.push(' (');
      // Email address.
      if (this.email !== '') {
        line.push(this.email);
      }
      // Phone numbers.
      this.phoneFields.forEach(function (phoneField, i) {
        var label;

        if (i !== 0 || this.email !== '') {
          line.push(' - ');
        }
        label = phoneField.getLabel();
        if (label !== '') {
          line.push('[', beautifyLabel(label), '] ');
        }
        line.push(phoneField.getPhoneNumber());
      });
      line.push(')');
    }
    line.push('\n');
    return line;
  };

  /*
   * Use the extracted data to build a line of HTML text displaying all the
   * collected data about the contact.
   */
  this.getHtmlLine = function () {
    var line, imgCount;

    line = [];

    line.push('<li>');
    // Profile photo.
    if (this.photo !== '') {
      imgCount = Object.keys(inlineImages).length;
      inlineImages['contact-img-' + imgCount] = UrlFetchApp.fetch(this.photo).getBlob().setName('contact-img-' + imgCount);
      line.push('<img src="cid:contact-img-' + imgCount + '" style="height:1.4em;margin-right:0.4em" />');
    }
    // Full name.
    line.push(this.fullName);
    // Age.
    if (this.age !== '') {
      line.push(' - ', _('Age'), ': ', this.age);
    }
    if (this.email !== '' || typeof this.phoneFields !== 'undefined') {
      line.push(' (');
      // Email address.
      if (this.email !== '') {
        line.push(this.email);
      }
      // Phone fields.
      this.phoneFields.forEach(function (phoneField, i) {
        var label;

        if (i !== 0 || this.email !== '') {
          line.push(' - ');
        }
        label = phoneField.getLabel();
        if (label !== '') {
          line.push('[', beautifyLabel(label), '] ');
        }
        line.push('<a href="tel:', phoneField.getPhoneNumber(), '">', phoneField.getPhoneNumber(), '</a>');
      });
      line.push(')');
    }
    // Mailto link.
    if (this.email !== '') {
      line.push(' <a href="mailto:', this.email, '">', _('send email now'), '</a>');
    }

    return line;
  };
};

// Start the notification service.
function start () {
  stop();
  ScriptApp.newTrigger('normal')
  .timeBased()
  .atHour(notificationHour)
  .everyDays(1)
  .inTimezone(myTimeZone)
  .create();
}

// Stop the notification service.
function stop () {
  var triggers;
  // Delete all the triggers.
  triggers = ScriptApp.getProjectTriggers();
  for (var i = 0; i < triggers.length; i++) {
    ScriptApp.deleteTrigger(triggers[i]);
  }
}

// Check if notification service is running.
function status () {
  var toLog = 'Notifications are';

  if (ScriptApp.getProjectTriggers().length < 1) {
    toLog += ' not';
  }
  toLog += ' running.';
  Logger.log(toLog);
  if (!noLog && sendLog) {
    MailApp.sendEmail({
      to: myEmail,
      subject: 'Status for birthday-notification',
      body: Logger.getLog()
    });
  }
}

// Normal function call (This function is called by the timed trigger).
function normal () {
  checkBirthdays();
}

/*
 * Use this function to test the script. Edit the date in the debugging
 * configuration above and click "Run"->"test" in the menu at the top
 * of the Google script interface.
 */
function test () {
  var testDate;

  testDate = new Date(fakeTestDate);
  doLog('Testing.');
  doLog('Test date: ' + testDate);
  checkBirthdays(testDate);
}

Please help me and thanks in advance.

regards,
Arjun Chavda

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.