Mail Ext Paste 3

 {

  "manifest_version": 3,
  "name": "Gmail AI Assistant",
  "version": "0.5.0",
  "description": "Intelligently sorts and prioritizes your emails.",
  "permissions": [
    "storage",
    "activeTab",
    "scripting",
    "identity"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [
    {
      "matches": [
        "https://mail.google.com/*"
      ],
      "js": [
        "content.js"
      ],
      "css": [
        "styles.css"
      ]
    }
  ],
  "action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "images/icon16.png",
      "48": "images/icon48.png",
      "128": "images/icon128.png"
    }
  },
  "icons": {
    "16": "images/icon16.png",
    "48": "images/icon48.png",
    "128": "images/icon128.png"
  },
  "oauth2": {
    "client_id": "YOUR_CLIENT_ID.apps.googleusercontent.com",
    "scopes": [
      "https://www.googleapis.com/auth/gmail.modify"
    ]
  }
}
```javascript
// background.js

console.log("Gmail AI Assistant background script loaded.");

// Set default settings when the extension is installed.
chrome.runtime.onInstalled.addListener(() => {
    chrome.storage.sync.set({
        senderCounts: {},
        settings: {
            enableRepetitive: true,
            enablePromotional: true,
            enablePersonal: true
        }
    });
});


/**
 * Handles messages sent from the content script to perform actions.
 */
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.action === 'createFilter') {
        getAuthToken(token => {
            createFilter(token, request.data.senderEmail);
        });
    } else if (request.action === 'markPriority') {
        getAuthToken(token => {
            applyPriorityLabel(token, request.data.threadId);
        });
    }
    return true; // Indicates that the response will be sent asynchronously.
});

/**
 * Prompts the user for authentication and retrieves an OAuth 2.0 token.
 * @param {function(string)} callback - The function to call with the retrieved token.
 */
function getAuthToken(callback) {
    chrome.identity.getAuthToken({ interactive: true }, (token) => {
        if (chrome.runtime.lastError) {
            console.error(chrome.runtime.lastError.message);
            return;
        }
        callback(token);
    });
}

/**
 * Creates a new label named "Priority" if it doesn't already exist.
 * @param {string} token - The OAuth 2.0 token.
 * @returns {Promise<string>} A promise that resolves with the ID of the "Priority" label.
 */
async function getOrCreatePriorityLabelId(token) {
    // First, list existing labels to see if "Priority" already exists.
    const listResponse = await fetch('[https://gmail.googleapis.com/gmail/v1/users/me/labels](https://gmail.googleapis.com/gmail/v1/users/me/labels)', {
        headers: { 'Authorization': `Bearer ${token}` }
    });
    const listData = await listResponse.json();
    const priorityLabel = listData.labels.find(label => label.name === 'Priority');

    if (priorityLabel) {
        return priorityLabel.id; // Return existing label ID
    }

    // If it doesn't exist, create it.
    const createResponse = await fetch('[https://gmail.googleapis.com/gmail/v1/users/me/labels](https://gmail.googleapis.com/gmail/v1/users/me/labels)', {
        method: 'POST',
        headers: {
            'Authorization': `Bearer ${token}`,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            name: 'Priority',
            labelListVisibility: 'labelShow',
            messageListVisibility: 'show'
        })
    });
    const createData = await createResponse.json();
    console.log('Created "Priority" label:', createData);
    return createData.id;
}

/**
 * Applies the "Priority" label to a specific email thread.
 * @param {string} token - The OAuth 2.0 token.
 * @param {string} threadId - The ID of the thread to label.
 */
async function applyPriorityLabel(token, threadId) {
    const labelId = await getOrCreatePriorityLabelId(token);
    const response = await fetch(`https://gmail.googleapis.com/gmail/v1/users/me/threads/${threadId}/modify`, {
        method: 'POST',
        headers: {
            'Authorization': `Bearer ${token}`,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            addLabelIds: [labelId]
        })
    });
    const data = await response.json();
    console.log('Applied Priority label to thread:', data);
}

/**
 * Creates a Gmail filter to archive emails from a specific sender.
 * @param {string} token - The OAuth 2.0 token.
 * @param {string} senderEmail - The email address of the sender to filter.
 */
async function createFilter(token, senderEmail) {
    const filter = {
        criteria: { from: senderEmail },
        action: { addLabelIds: ['TRASH'] } // Archives and moves to trash
    };

    const response = await fetch('[https://gmail.googleapis.com/gmail/v1/users/me/settings/filters](https://gmail.googleapis.com/gmail/v1/users/me/settings/filters)', {
        method: 'POST',
        headers: {
            'Authorization': `Bearer ${token}`,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(filter)
    });

    const data = await response.json();
    console.log('Filter created:', data);
}
```javascript
// content.js

console.log("Gmail AI Assistant content script loaded and running.");

const PROMOTION_KEYWORDS = [
    'unsubscribe', 'view in browser', 'no longer wish', 'special offer',
    'limited time', 'percent off', 'free shipping', 'view this email'
];

/**
 * Scans all visible emails for various patterns and injects contextual prompts based on user settings.
 */
function processVisibleEmails() {
    const emailRows = document.querySelectorAll('tr.zA');
    if (emailRows.length === 0) return;

    // Get user settings and sender counts from storage
    chrome.storage.sync.get(['senderCounts', 'settings'], (result) => {
        let counts = result.senderCounts || {};
        const settings = result.settings || {
            enableRepetitive: true,
            enablePromotional: true,
            enablePersonal: true
        };
        let updated = false;

        emailRows.forEach(row => {
            if (row.dataset.promptInjected) return;

            const senderEl = row.querySelector('.yW span[email]');
            if (senderEl) {
                const senderEmail = senderEl.getAttribute('email');
                const senderName = senderEl.getAttribute('name');

                // --- 1. Personal Conversation Logic ---
                const threadCountEl = row.querySelector('.bA4 span');
                if (settings.enablePersonal && threadCountEl && parseInt(threadCountEl.innerText) > 2) {
                    const threadId = row.closest('tr').getAttribute('data-thread-id');
                    if (threadId) {
                        injectPersonalConversationPrompt(row, senderName, threadId);
                        row.dataset.promptInjected = 'true';
                        return;
                    }
                }

                // --- 2. Repetitive Sender Logic ---
                if (!counts[senderEmail]) {
                    counts[senderEmail] = 0;
                }
                counts[senderEmail] += 1;
                updated = true;

                const threshold = 4;
                if (settings.enableRepetitive && counts[senderEmail] >= threshold) {
                    injectRepetitiveEmailPrompt(row, senderName, senderEmail, counts[senderEmail]);
                    row.dataset.promptInjected = 'true';
                    return;
                }

                // --- 3. Promotional Email Logic ---
                const snippetEl = row.querySelector('.y2');
                if (settings.enablePromotional && snippetEl) {
                    const snippetText = snippetEl.innerText.toLowerCase();
                    if (PROMOTION_KEYWORDS.some(keyword => snippetText.includes(keyword))) {
                        injectPromotionPrompt(row, senderName);
                        row.dataset.promptInjected = 'true';
                        return;
                    }
                }
            }
        });

        if (updated) {
            chrome.storage.sync.set({ senderCounts: counts });
        }
    });
}


/**
 * Injects a prompt for personal conversations.
 * @param {HTMLElement} targetRow The email row.
 * @param {string} senderName The sender's name.
 * @param {string} threadId The ID of the email thread.
 */
function injectPersonalConversationPrompt(targetRow, senderName, threadId) {
    const promptContainer = createPromptContainer();
    const promptContent = document.createElement('div');
    promptContent.className = 'gmail-ai-prompt personal';

    promptContent.innerHTML = `
        <div class="prompt-icon">💬</div>
        <div class="prompt-text">This looks like an important conversation with <strong>${senderName}</strong>. Mark as priority?</div>
        <div class="prompt-actions">
            <button class="prompt-button yes" data-action="mark-priority">Mark Priority</button>
            <button class="prompt-button no" data-action="dismiss">Dismiss</button>
        </div>
    `;

    promptContainer.firstChild.appendChild(promptContent);
    targetRow.parentNode.insertBefore(promptContainer, targetRow);

    promptContainer.querySelector('[data-action="dismiss"]').addEventListener('click', (e) => { e.stopPropagation(); promptContainer.remove(); });
    promptContainer.querySelector('[data-action="mark-priority"]').addEventListener('click', (e) => {
        e.stopPropagation();
        chrome.runtime.sendMessage({ action: 'markPriority', data: { threadId } });
        promptContainer.remove();
    });
}

/**
 * Injects a prompt for likely promotions.
 */
function injectPromotionPrompt(targetRow, senderName) {
    const promptContainer = createPromptContainer();
    const promptContent = document.createElement('div');
    promptContent.className = 'gmail-ai-prompt promotion';

    promptContent.innerHTML = `
        <div class="prompt-icon">🛍️</div>
        <div class="prompt-text">This looks like a promotional email from <strong>${senderName}</strong>.</div>
        <div class="prompt-actions">
            <button class="prompt-button yes" data-action="unsubscribe">Unsubscribe</button>
            <button class="prompt-button no" data-action="dismiss">Dismiss</button>
        </div>
    `;

    promptContainer.firstChild.appendChild(promptContent);
    targetRow.parentNode.insertBefore(promptContainer, targetRow);

    promptContainer.querySelector('[data-action="dismiss"]').addEventListener('click', (e) => { e.stopPropagation(); promptContainer.remove(); });
    promptContainer.querySelector('[data-action="unsubscribe"]').addEventListener('click', (e) => {
        e.stopPropagation();
        alert('Automated unsubscribe coming in a future update!');
        promptContainer.remove();
    });
}

/**
 * Injects the prompt for repetitive emails.
 */
function injectRepetitiveEmailPrompt(targetRow, senderName, senderEmail, count) {
    const promptContainer = createPromptContainer();
    const promptContent = document.createElement('div');
    promptContent.className = 'gmail-ai-prompt repetitive';

    promptContent.innerHTML = `
        <div class="prompt-icon">💡</div>
        <div class="prompt-text">You've received <strong>${count}</strong> emails from <strong>${senderName}</strong>. Would you like to create a filter?</div>
        <div class="prompt-actions">
            <button class="prompt-button yes" data-action="create-filter">Create Filter</button>
            <button class="prompt-button no" data-action="dismiss">Dismiss</button>
        </div>
    `;
   
    promptContainer.firstChild.appendChild(promptContent);
    targetRow.parentNode.insertBefore(promptContainer, targetRow);

    promptContainer.querySelector('[data-action="dismiss"]').addEventListener('click', (e) => { e.stopPropagation(); promptContainer.remove(); });
    promptContainer.querySelector('[data-action="create-filter"]').addEventListener('click', (e) => {
        e.stopPropagation();
        chrome.runtime.sendMessage({ action: 'createFilter', data: { senderEmail } });
        promptContainer.remove();
    });
}

function createPromptContainer() {
    const container = document.createElement('tr');
    container.className = 'gmail-ai-prompt-container';
    const cell = document.createElement('td');
    cell.colSpan = "100%";
    container.appendChild(cell);
    return container;
}

function observeGmail() {
    const observer = new MutationObserver((mutationsList) => {
        for(const mutation of mutationsList) {
            if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                setTimeout(processVisibleEmails, 500);
                return;
            }
        }
    });

    observer.observe(document.body, { childList: true, subtree: true });
    console.log("Mutation observer is now watching the Gmail interface.");
    setTimeout(processVisibleEmails, 1000);
}

const initInterval = setInterval(() => {
    if (document.querySelector('.Cp')) {
        clearInterval(initInterval);
        observeGmail();
    }
}, 500);
```css
/* styles.css */

/* --- In-Page Prompt Styles --- */

.gmail-ai-prompt-container {
    border: none !important;
    box-shadow: none !important;
}

.gmail-ai-prompt {
    border-radius: 8px;
    padding: 12px 16px;
    margin: 6px 16px 6px 72px;
    font-family: 'Google Sans', Roboto, Arial, sans-serif;
    font-size: 14px;
    display: flex;
    align-items: center;
    gap: 16px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}

.gmail-ai-prompt.repetitive {
    background-color: #f0f4f9;
    border: 1px solid #d4e3fb;
}

.gmail-ai-prompt.promotion {
    background-color: #fce8e6;
    border: 1px solid #f9d9d6;
}

.gmail-ai-prompt.promotion .prompt-text strong {
    color: #c5221f;
}

.gmail-ai-prompt.personal {
    background-color: #e6f4ea;
    border: 1px solid #cce8d4;
}

.gmail-ai-prompt.personal .prompt-text strong {
    color: #1e8e3e;
}

.prompt-icon {
    font-size: 20px;
}

.prompt-text {
    flex-grow: 1;
    color: #3c4043;
}

.prompt-text strong {
    font-weight: 500;
    color: #1a73e8;
}

.prompt-actions {
    display: flex;
    gap: 8px;
}

.prompt-button {
    background-color: transparent;
    border: 1px solid #dadce0;
    border-radius: 4px;
    padding: 8px 16px;
    font-family: inherit;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    transition: background-color 0.2s, box-shadow 0.2s;
}

.prompt-button.yes {
    background-color: #1a73e8;
    color: white;
    border-color: #1a73e8;
}

.prompt-button.yes:hover {
    background-color: #287ae6;
    box-shadow: 0 1px 2px 0 rgba(60,64,67,0.3), 0 1px 3px 1px rgba(60,64,67,0.15);
}

.gmail-ai-prompt.promotion .prompt-button.yes {
    background-color: #d93025;
    border-color: #d93025;
}

.gmail-ai-prompt.promotion .prompt-button.yes:hover {
    background-color: #e04a40;
}

.gmail-ai-prompt.personal .prompt-button.yes {
    background-color: #1e8e3e;
    border-color: #1e8e3e;
}

.gmail-ai-prompt.personal .prompt-button.yes:hover {
    background-color: #25a24c;
}

.prompt-button.no {
    color: #5f6368;
}

.prompt-button.no:hover {
    background-color: #f1f3f4;
}


/* --- Popup Styles --- */

body {
    font-family: 'Google Sans', Roboto, Arial, sans-serif;
    width: 280px;
    padding: 0;
    background-color: #f8f9fa;
}

.popup-header {
    background-color: #4285f4;
    color: white;
    padding: 16px;
    text-align: center;
}

.popup-header h1 {
    font-size: 18px;
    margin: 0;
    font-weight: 500;
}

.settings-list {
    padding: 8px 0;
}

.setting-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px 16px;
    border-bottom: 1px solid #e0e0e0;
}

.setting-item:last-child {
    border-bottom: none;
}

.setting-label {
    font-size: 14px;
    color: #3c4043;
}

/* The switch - the box around the slider */
.switch {
  position: relative;
  display: inline-block;
  width: 34px;
  height: 20px;
}

/* Hide default HTML checkbox */
.switch input {
  opacity: 0;
  width: 0;
  height: 0;
}

/* The slider */
.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #ccc;
  -webkit-transition: .4s;
  transition: .4s;
  border-radius: 20px;
}

.slider:before {
  position: absolute;
  content: "";
  height: 14px;
  width: 14px;
  left: 3px;
  bottom: 3px;
  background-color: white;
  -webkit-transition: .4s;
  transition: .4s;
  border-radius: 50%;
}

input:checked + .slider {
  background-color: #4285f4;
}

input:focus + .slider {
  box-shadow: 0 0 1px #4285f4;
}

input:checked + .slider:before {
  -webkit-transform: translateX(14px);
  -ms-transform: translateX(14px);
  transform: translateX(14px);
}
```html
<!-- popup.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Gmail AI Assistant Settings</title>
    <link href="styles.css" rel="stylesheet">
</head>
<body>
    <div class="popup-header">
        <h1>AI Assistant Settings</h1>
    </div>
    <div class="settings-list">
        <div class="setting-item">
            <span class="setting-label">Repetitive Email Prompts</span>
            <label class="switch">
                <input type="checkbox" id="enableRepetitive">
                <span class="slider"></span>
            </label>
        </div>
        <div class="setting-item">
            <span class="setting-label">Promotional Email Prompts</span>
            <label class="switch">
                <input type="checkbox" id="enablePromotional">
                <span class="slider"></span>
            </label>
        </div>
        <div class="setting-item">
            <span class="setting-label">Personal Conversation Prompts</span>
            <label class="switch">
                <input type="checkbox" id="enablePersonal">
                <span class="slider"></span>
            </label>
        </div>
    </div>
    <script src="popup.js"></script>
</body>
</html>
```javascript
// popup.js

document.addEventListener('DOMContentLoaded', () => {
    const repetitiveToggle = document.getElementById('enableRepetitive');
    const promotionalToggle = document.getElementById('enablePromotional');
    const personalToggle = document.getElementById('enablePersonal');

    // Load current settings and update the UI
    chrome.storage.sync.get('settings', (data) => {
        if (data.settings) {
            repetitiveToggle.checked = data.settings.enableRepetitive;
            promotionalToggle.checked = data.settings.enablePromotional;
            personalToggle.checked = data.settings.enablePersonal;
        }
    });

    // Save settings when a toggle is changed
    repetitiveToggle.addEventListener('change', (event) => {
        updateSettings({ enableRepetitive: event.target.checked });
    });
    promotionalToggle.addEventListener('change', (event) => {
        updateSettings({ enablePromotional: event.target.checked });
    });
    personalToggle.addEventListener('change', (event) => {
        updateSettings({ enablePersonal: event.target.checked });
    });
});

/**
 * Updates the settings in chrome.storage.
 * @param {object} newSettings - An object with the settings to update.
 */
function updateSettings(newSettings) {
    chrome.storage.sync.get('settings', (data) => {
        const updatedSettings = { ...data.settings, ...newSettings };
        chrome.storage.sync.set({ settings: updatedSettings });
    });
}
```
// Create dummy icon files named icon16.png, icon48.png, and icon128.png
// and place them in an 'images' folder. For now, they can be any simple image.

Comments