# How HelloGitHub's Email Notification System Sends Daily Project Recommendations

> Discover how HelloGitHub's Python bot sends daily project recommendations by scraping GitHub events, filtering by popularity, and delivering via SMTP. Learn the system's mechanics.

- Repository: [削微寒/HelloGitHub](https://github.com/521xueweihan/HelloGitHub)
- Tags: internals
- Published: 2026-02-25

---

**HelloGitHub's email notification system uses a Python bot to scrape recent GitHub star events, filter them by configurable popularity thresholds, format the results as an HTML table, and deliver daily recommendations via SMTP.**

The `521xueweihan/HelloGitHub` repository includes a lightweight, automated **email notification system** that curates trending open-source projects and delivers them directly to subscribers' inboxes. Implemented in [`script/github_bot/github_bot.py`](https://github.com/521xueweihan/HelloGitHub/blob/main/script/github_bot/github_bot.py), this self-contained Python script monitors public GitHub activity through the Events API, applies quality filtering criteria, and manages the complete delivery pipeline from data aggregation to email transmission.

## How the Notification Pipeline Works

The system processes recommendations through a five-stage pipeline defined in [`github_bot.py`](https://github.com/521xueweihan/HelloGitHub/blob/main/github_bot.py). Each stage is handled by discrete functions that transform raw GitHub events into a formatted email ready for delivery.

### Fetching Recent Star Events

The data collection begins in `get_all_data()`, located at lines 70–96, which paginates through the GitHub `received_events` endpoint for the user specified in the `ACCOUNT` configuration variable. The function retrieves up to 10 pages of event history (approximately 300 events) to ensure comprehensive coverage of recent activity across the user's network.

### Filtering for Relevant Activity

Once collected, events pass through `check_condition()` (lines 104–118) to isolate meaningful star actions. This filter strictly selects `WatchEvent` items where the `action` field equals `started`, ensuring the repository was starred rather than unstarred. The function also verifies the event belongs to a different user (excluding self-activity) and occurred within the configurable `DAY` window. The `analyze()` function (lines 121–131) aggregates these valid events into a deduplicated list for further processing.

### Enforcing Quality Thresholds

The enrichment phase occurs in `get_stars()` (lines 134–162), which queries each repository's current `stargazers_count` via the API URL extracted from `fi_data['repo']['url']`. Projects with fewer stars than the `STARS` threshold (defaulting to 100) are discarded, while repositories returning unknown star counts (marked as `-1`) are retained as a fallback. The remaining items are sorted in descending order by popularity to prioritize the most significant projects in the final email.

### Generating HTML Email Content

The `make_content()` function (referenced at lines 211–214) orchestrates content generation by iterating over the curated project list. Each entry is injected into an HTML table row template, with all rows concatenated and inserted into `CONTENT_FORMAT`—an HTML skeleton defined at lines 56–67 that provides the structural layout for the email body. This produces a complete HTML document containing repository avatars, names, links, timestamps, and star counts.

### Delivering via SMTP

Finally, `send_email()` (lines 35–42) constructs a `MIMEText` message using the generated HTML body and sets the *From*, *To*, and *Subject* headers from the `MAIL` configuration and `RECEIVERS` list. The actual transmission occurs through `SMTP_SSL` via `connect()`, `login()`, and `sendmail()` (lines 202–207), establishing an encrypted connection to the configured mail server. Error handling logs delivery failures without aborting the script, ensuring the bot remains operational even if individual messages fail.

## Configuring the Email System

The notification behavior is controlled through module-level constants in [`github_bot.py`](https://github.com/521xueweihan/HelloGitHub/blob/main/github_bot.py) that require no database or external configuration files:

- **`ACCOUNT`**: The GitHub username whose received events provide the data source
- **`DAY`**: Integer defining how many days back to search for star events
- **`STARS`**: Minimum star count threshold (default 100) for project inclusion
- **`MAIL`**: Dictionary containing `mail`, `username`, `password`, `host`, and `port` for SMTP authentication
- **`RECEIVERS`**: List of email addresses that will receive the daily digest

## Running and Testing the Bot

Execute the notification system manually to trigger an immediate send:

```bash
python script/github_bot/github_bot.py

```

To inspect the generated content without sending email, call `make_content()` directly:

```python
from script.github_bot.github_bot import make_content

rows = make_content()
print(''.join(rows))  # View the HTML table rows

```

For testing SMTP configuration without pulling live GitHub data, manually construct content and invoke the sender:

```python
from script.github_bot.github_bot import send_email, RECEIVERS

test_content = [
    """<tr>
         <td><img src="https://avatars.githubusercontent.com/u/1?v=4" width=32px></td>
         <td><a href="https://github.com/octocat">octocat</a></td>
         <td><a href="https://github.com/octocat/Hello-World">Hello-World</a></td>
         <td>2024-02-25 12:00:00</td>
         <td>12345</td>
       </tr>"""
]

send_email(RECEIVERS, test_content)

```

## Summary

- The system polls the GitHub `received_events` API for recent `WatchEvent` activity across a configurable user account.
- **Filtering logic** in `check_condition()` ensures only external star actions from the last `DAY` days are processed.
- **Quality control** via `get_stars()` enforces a minimum star threshold (default 100) and sorts results by popularity.
- **Content generation** produces an HTML table via `make_content()` using the `CONTENT_FORMAT` template.
- **Delivery** uses Python's `smtplib.SMTP_SSL` for encrypted transmission to all addresses in `RECEIVERS`.

## Frequently Asked Questions

### What GitHub API endpoint does the email notification system use to discover projects?

The system queries the `received_events` endpoint for the user specified in the `ACCOUNT` variable, as implemented in `get_all_data()` at lines 70–96 of [`github_bot.py`](https://github.com/521xueweihan/HelloGitHub/blob/main/github_bot.py). This endpoint returns public events from the user's network, including stars from people they follow, rather than scanning global trending repositories.

### How does the system prevent low-quality projects from being recommended?

Two mechanisms enforce quality standards. First, `check_condition()` filters for genuine star events while excluding the bot owner's own activity. Second, `get_stars()` (lines 134–162) fetches each repository's current star count and discards projects below the `STARS` threshold, ensuring only established repositories with significant community interest are included.

### What SMTP configuration is required to enable email delivery?

The `MAIL` dictionary must contain valid credentials including `mail` (sender address), `username`, `password`, `host` (SMTP server), and `port` (typically 465 for SSL). The `send_email()` function uses these values to establish an `SMTP_SSL` connection and authenticate before transmitting the `MIMEText` message to all addresses listed in `RECEIVERS`.

### Can the email notification system run on a schedule without manual intervention?

Yes, the script is designed for automation through cron jobs or system timers. Since the configuration is code-based and the bot logs errors without crashing, it can execute periodically (e.g., daily) to check for new star events and automatically deliver recommendations whenever the `DAY` window detects fresh activity meeting the threshold criteria.