`; } logoElement.innerHTML = html; } } function HideBackButton() { var logoElement = document.getElementById("logo"); if (logoElement) { logoElement.innerHTML = ` Groups.io `; } } function goBack() { history.back(); } // submitEvent acts like .submit(), except it is compatible with the app, by using events instead. function submitEvent(ele) { console.log("in submitEvent"); if (ele.startsWith('#')) { ele = ele.slice(1); } document.getElementById(ele).submit(); return; /* const theEvent = new CustomEvent('submit', { bubbles: true, cancelable: true }); if (typeof ele === 'string' || ele instanceof String) { if (ele.startsWith("#") == true) { ele = ele.slice(1); } if (document.getElementById(ele).dispatchEvent(theEvent) == true) { // if not cancelled, do normal submit console.log("calling submit"); document.getElementById(ele).submit(); } return; } // assume ele is the element if (ele.dispatchEvent(theEvent) == true) { // if not cancelled, do normal submit console.log("calling submit"); ele.submit(); } */ } // gioDestroy is a convenience function for destroy callbacks function gioDestroy(eventCB) { let internalGioDestroy = function(evt) { // do not activate on infinite scroll events if (evt.detail.target !== undefined && evt.detail.target.id != "maincontent-refresh") { console.log("Ignoring infinite scroll event"); return; } console.log("Calling destroy callback"); eventCB(evt); } document.body.addEventListener("htmx:beforeSwap", internalGioDestroy, {once: true}); document.body.addEventListener("htmx:historyCacheMiss", internalGioDestroy, {once: true}); } var drawerCloseFunc = function(evt) { console.log("in drawerCloseFunc"); // Find all elements with the class 'drawer' var drawers = document.querySelectorAll('.drawer'); // Iterate over each element and call closeDrawer() on each drawers.forEach(function(obj) { drawerObj.closeDrawer(obj); }); $('.modal').modal('hide'); } document.body.addEventListener('htmx:beforeSwap', drawerCloseFunc); document.body.addEventListener('htmx:historyCacheMiss', drawerCloseFunc); var keydownFunc = function(event) { var tagName = event.target.tagName.toLowerCase(); if (tagName === 'input' || tagName === 'textarea' || event.target.isContentEditable) { if (event.key === 'Escape') { event.target.blur(); } return; } // check if the viewimages viewer is up let element = document.getElementById('overlay'); if (element && element.classList.contains('visible')) { return; } console.log("HERE: " + event.key + " " + event.ctrlKey + " " + event.shiftKey + " " + event.metaKey); if (event.ctrlKey && event.shiftKey && (event.key === '?' || event.key === '/')) { event.preventDefault(); // Prevent the default action // Show the modal dialog for keyboard shortcuts $('#shortcutModal').modal('show'); return; } $('#shortcutModal').modal('hide'); if (event.key.toLowerCase() === 'g') { // For Windows and Linux if (event.ctrlKey) { event.preventDefault(); showAutocompleteModal("groupnavigator"); return; } } // Check if the pressed key is '/' if ((event.key === 'f' || event.key === 'F') && event.shiftKey) { if (navigator.platform.toUpperCase().indexOf('MAC') >= 0) { if (event.metaKey) { event.preventDefault(); // Prevent the default action // Focus on the search box let box = document.getElementById('searchbox') if (box != null) { document.getElementById('searchbox').focus(); } } } else { // For Windows and Linux if (event.ctrlKey) { event.preventDefault(); // Prevent the default action // Focus on the search box let box = document.getElementById('searchbox') if (box != null) { document.getElementById('searchbox').focus(); } } } } } document.addEventListener('keydown', keydownFunc); var removeDrawerCloseFunc = function(evt) { document.body.removeEventListener('htmx:beforeSwap', drawerCloseFunc); document.body.removeEventListener('htmx:historyCacheMiss', drawerCloseFunc); document.removeEventListener('keydown', keydownFunc); } document.body.addEventListener("htmx:historyCacheMiss", removeDrawerCloseFunc, {once: true});

Features

Pricing

Why Email Groups?


The Most Advanced Features Of Any Group System



Better archive organization with hashtags

Tag a message topic by including a #hashtag in the subject.


Hashtags let you control and organize your archives. Tags can have an expiration; topics with those tags will be automatically deleted after the specified time. Tags can also be set as No Email, for when you want to include messages in the archive but you don't want to have them sent to the group. Tags can be restricted to a predefined set. And of course the archives are searchable by tag.



Only The Messages You Want

Avoid email overload.


You can mute individual topics and hashtags. And we have a set of powerful subscription options. You can receive every message. Or you can opt to receive only the first message in a topic, with the option to follow the topic later. Or you can opt to receive only messages in topics that you start. Finally, you can opt to receive no emails at all.



Advanced group management.

Groups.io supports all the options you'd expect in a modern groups service.


Create an announcement, moderated, or restricted group. Customize the various welcome, goodbye, monthly, and pending subscription messages. Then define multiple owners and moderators, using our full permissions system. Monitor the group through the activity log, and track email delivery to members. Approve messages from moderated users either through the website or via email. Automatically moderate or lock individual group topics after a set number of days. Relax knowing that Groups.io handles bounces and autoresponders automatically, and that we're DMARC compatible.



Powerful integrations

Groups.io works with the services that you and your team already use. Premium groups support the following integrations:


  • Email - Create a receive-only email address that posts to your group.
  • Feeds - Post items from RSS feeds to your group.
  • GitHub - Post to your group whenever code is committed to a repository.
  • Trello - Post to your group whenever there is activity in a Trello board.

And we're adding more integrations all the time.



Member synchronization

Sync your members across services.


If you have a Slack Team, you can sync it with your Groups.io Premium group. Then, when someone joins your group, they will be automatically invited to join your Slack Team. And if someone leaves your group, they will be removed from your Slack Team.



Powerful additional features

Messages are just the start.


Each Premium group has many additional features, each of which is fully integrated with your group. Start with the calendar, where you can schedule events and send reminders. You can set up an unlimited number of chat rooms. There's also a poll feature, where you can ask questions of your group. Each group also has a full featured database, where you can define tables with different column types. There are sections for uploading photos and files. And a wiki, for storing group knowledge. Finally, each Premium group can have an unlimited number of subgroups.



Start a Groups.io Group