Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Website Feature]: Newsletter Signup #727

Closed
2 of 7 tasks
ssandino opened this issue Jan 29, 2024 · 4 comments
Closed
2 of 7 tasks

[Website Feature]: Newsletter Signup #727

ssandino opened this issue Jan 29, 2024 · 4 comments
Assignees
Labels
feature New feature or request website Issues concerning Website

Comments

@ssandino
Copy link
Member

ssandino commented Jan 29, 2024

Is there an existing request for this feature?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe.

Currently, we do not offer a newsletter signup option, and individuals who donate are not automatically added to the newsletter list. Our newsletters are managed through Mailchimp, and the list is directly maintained there.

Describe the solution/feature

Handle Newsletter Subscriptions

  • Newsletter Signup Page: Create new page ".../updates" with the respective language files.
  • Add Form: This page should feature a form with the following fields (* required):
    Email *, First Name, Gender, Language * (dropdown pre-filled with the site language plus DE as other option, as email campaign will be in German for German speakers!), Country * (pre-filled with IP country),
    Information entered should be sent directly to Mailchimp via API.
  • Add footer link: Include a signup link in the website footer that redirects to ".../updates."
  • Popup Signup Form: Implement a popup signup form that can be triggered on any page of the site. The popup should appear after 20 seconds of user activity. We should have the ability to enable or disable this feature on specific pages, as it may not be desired on the landing page but could be valuable on certain content pages. This functionality will be utilized as part of a campaign aimed at engaging users before they typically leave the website.
  • Automatic Signup for Donors: New donors should be added automatically to newsletter list with Mailchimp API. Existing contributors should be able to toggle newsletter subscription in their dashboard. This action will trigger an API request to Mailchimp. If the user is already on the mailing list and changes their status from subscribed to unsubscribed, this change will be reflected. If the user is not yet on the list, it adds the user and signs them up.

Handle Newsletter Unsubscriptions
Newsletter recipients should unsubscribe directly from the newsletter using the standard Mailchimp unsubscribe tag. There is nothing else to do in this regard, as unsubscribes are handled by Mailchimp.

Describe alternatives you've considered

We already had a form on the old page, which covered Nr. 2, but it wasn't directly connected to Mailchimp.

Criteria for Completion

No response

Anything else?

No response

Code of Conduct

  • I've read the Code of Conduct and understand my responsibilities as a member of the Social Income community
@ssandino ssandino added feature New feature or request website Issues concerning Website labels Jan 29, 2024
@ssandino
Copy link
Member Author

@mkue anything else that comes to mind?

@ssandino
Copy link
Member Author

@brennerthomas, as a reference for how we handled newsletter subscriptions in the old environment, this information might be helpful. Difference: In the past, we also saved the values in Firebase, which is no longer necessary. We can now directly save them in Mailchimp without the need for syncing back and forth.

const client = require("@mailchimp/mailchimp_marketing");
const functions = require("firebase-functions");
const admin = require("firebase-admin");

module.exports.addToMailchimp = async (email, firstname, lastname, country, gender) => {
    client.setConfig({
        apiKey: process.env.MAILCHIMP_KEY,
        server: process.env.MAILCHIMP_SERVER
    });

    try {
        let mailchimpGender = 'Other'
        if (gender === 'female') mailchimpGender = 'Female'
        if (gender === 'male') mailchimpGender = 'Male'

        await client.lists.addListMember(process.env.MAILCHIMP_LIST_ID, {
            email_address: email,
            status: "subscribed",
            merge_fields: {
                'FNAME': firstname,
                'LNAME':  lastname,
                'COUNTRY': country,
                'GENDER': mailchimpGender
            }
        });
        functions.logger.info(`Added ${email} to mailchimp`);
    } catch (error) {
        if (error.response?.body?.title === 'Member Exists') {
            functions.logger.info(`Member ${email} already exists`);
        } else {
            functions.logger.error(`Could not add new user ${email} to mailchimp`, error);
        }
    }
};

// https://mailchimp.com/developer/marketing/api/list-members/list-members-info/
async function fetchMailchimpSubscribers() {
    client.setConfig({
        apiKey: process.env.MAILCHIMP_KEY,
        server: process.env.MAILCHIMP_SERVER
    });

    let subscriberList = [];
    try{
        // check suscriber list length
        const response = await client.lists.getListMembersInfo(
            process.env.MAILCHIMP_LIST_ID, 
            {
                fields: [
                    'total_items'
                ],
                sort_field: "timestamp_signup"
            }
        );

        const total_items = response.total_items;
        const max_count = 1000;
        const num_queries = (total_items / max_count ) >> 0;
        let range = n => Array.from(Array(n).keys());

        const getSubList = offset => {
            return client.lists.getListMembersInfo(
                process.env.MAILCHIMP_LIST_ID, 
                {
                    fields: [
                        'members',
                    ],
                    sort_field: "timestamp_signup",
                    count: max_count,
                    offset: max_count*offset,
                }
            );
        };
        const responses = await Promise.all(range(num_queries + 1).map(qi => getSubList(qi)));
        responses.forEach(response => {
            response.members.map(item => subscriberList.push(item))
        });
    } catch (error) {
        functions.logger.error(`Could not fetch suscribers list from mailchimp`, error);
    }
    return subscriberList;
}

module.exports.setNewsSubscribers = async () => {
    try{
        subscribers = await fetchMailchimpSubscribers();
        subscribers.forEach(item => {
            const subscribersCollection = admin.firestore().collection("news-subscribers").doc(item.id);
            subscribersCollection.set(item);
        });
    } catch (error) {
        functions.logger.error(`Could not populate news-subscribers firebase collection`, error);
    }
};

module.exports.getNewsletterSubscriptionByEmail = async (email) => {
    try{
        let dataSnapshot = await admin.firestore().collection("newsletter-subscribers").where("email", "==", email).get();

        let subscriberList = [];
        dataSnapshot.forEach(doc => {
            let doc_data = doc.data();
            doc_data['id'] = doc.id;
            subscriberList.push(doc_data);
        });

        if (subscriberList.length > 1){
            functions.logger.error("Inconsistent database state, found multiple entries.", email);
            return null;
        }

        if (subscriberList.length === 1) {
            if (subscriberList[0].monthly_newsletter_status){
                functions.logger.error("Email already subscribed to newsletter.", email);
                return null;
            }
            return subscriberList[0];
        }
        return true;
    } catch (error) {
        functions.logger.error(`Could not populate news-subscribers firebase collection`, error);
        return null;
    }
};

@ssandino ssandino linked a pull request Jan 29, 2024 that will close this issue
@ssandino
Copy link
Member Author

@brennerthomas I already connected a draft PR #732 with the basic structure for the new page and the linked language files.

@ssandino ssandino pinned this issue Feb 7, 2024
@brennerthomas
Copy link
Contributor

The decision was taken to implement SendGrid from Twilio in parallel. We will proceed in the following way:

  1. Build SendGridAPI similar to MailchimpAPI with equal functionality
  2. Migrate routes from website to Sendgrid
  3. Manual export of CSV contacts from Mailchimp to Sendgrid to keep existing contacts

@ssandino, @mkue ok for you?

@mkue mkue closed this as completed Jun 2, 2024
@mkue mkue unpinned this issue Jun 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request website Issues concerning Website
Projects
Development

Successfully merging a pull request may close this issue.

3 participants