> ## Documentation Index
> Fetch the complete documentation index at: https://docs.endorlabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Set up email integration

> Learn how to integrate your email addresses with Endor Labs and receive finding notifications

export const CodeFile = ({src, lang, expandable = true, maxLines = 15}) => {
  const [content, setContent] = useState(null);
  const [wrapperLang, setWrapperLang] = useState('text');
  const [error, setError] = useState('');
  const [copied, setCopied] = useState(false);
  const [isDark, setIsDark] = useState(false);
  const [expanded, setExpanded] = useState(false);
  useEffect(() => {
    const root = document.documentElement;
    setIsDark(root.classList.contains('dark'));
    const observer = new MutationObserver(() => {
      setIsDark(root.classList.contains('dark'));
    });
    observer.observe(root, {
      attributes: true,
      attributeFilter: ['class']
    });
    return () => {
      observer.disconnect();
    };
  }, []);
  useEffect(() => {
    if (!src) {
      setError('No src provided.');
      return undefined;
    }
    const ac = new AbortController();
    fetch(src, {
      signal: ac.signal
    }).then(r => {
      if (!r.ok) throw new Error(r.status + ' ' + r.statusText);
      return r.json();
    }).then(data => {
      setContent(data.content || '');
      if (data.lang) setWrapperLang(data.lang);
    }).catch(err => {
      if (err.name !== 'AbortError') {
        setError('Unable to load ' + src + ': ' + err.message);
      }
    });
    return () => {
      ac.abort();
    };
  }, [src]);
  const language = lang || wrapperLang || 'text';
  const handleCopy = () => {
    if (!content) return;
    navigator.clipboard.writeText(content).then(() => {
      setCopied(true);
      setTimeout(() => {
        setCopied(false);
      }, 2000);
    }).catch(() => {});
  };
  const toggleExpand = () => {
    setExpanded(v => !v);
  };
  const statusBoxStyle = variant => {
    const base = {
      padding: '12px 16px',
      borderRadius: '6px',
      fontSize: '14px'
    };
    if (variant === 'error') {
      return {
        ...base,
        background: isDark ? '#451a1a' : '#fef2f2',
        color: isDark ? '#fca5a5' : '#dc2626',
        border: '1px solid ' + (isDark ? '#7f1d1d' : '#fecaca')
      };
    }
    return {
      ...base,
      background: isDark ? '#1f2937' : '#f5f5f5',
      color: isDark ? '#9ca3af' : '#6b7280'
    };
  };
  const shellStyle = {
    position: 'relative',
    borderRadius: '8px',
    border: '1px solid ' + (isDark ? 'rgba(255,255,255,0.1)' : '#d1d5db'),
    overflow: 'hidden'
  };
  const copyBtnStyle = {
    position: 'absolute',
    top: '8px',
    right: '8px',
    padding: '4px 8px',
    fontSize: '12px',
    lineHeight: '1',
    border: '1px solid rgba(255,255,255,0.3)',
    borderRadius: '4px',
    background: 'rgba(255,255,255,0.15)',
    color: '#fff',
    cursor: 'pointer',
    zIndex: 2,
    transition: 'background 0.15s, color 0.15s'
  };
  const renderErrorBox = () => <div style={statusBoxStyle('error')}>{error}</div>;
  const renderLoadingBox = () => <div style={statusBoxStyle('loading')}>Loading…</div>;
  const countLogicalLines = text => {
    const normalized = text.replace(/\n+$/, '');
    if (normalized === '') {
      return 0;
    }
    return normalized.split('\n').length;
  };
  const lineCount = content ? countLogicalLines(content) : 0;
  const showTruncate = expandable && lineCount >= maxLines && !expanded;
  const showExpandToggle = expandable && lineCount >= maxLines;
  const LINE_HEIGHT_PX = 25;
  const previewMaxHeightPx = maxLines * LINE_HEIGHT_PX;
  const preStyle = {
    margin: 0,
    padding: '16px',
    overflow: 'auto',
    maxHeight: showTruncate ? previewMaxHeightPx + 'px' : 'none',
    overflowY: showTruncate ? 'hidden' : 'auto'
  };
  const toggleLinkStyle = {
    display: 'block',
    width: '100%',
    boxSizing: 'border-box',
    background: 'none',
    border: 'none',
    padding: '8px 16px 12px 16px',
    cursor: 'pointer',
    color: '#26D07C',
    fontSize: '13px',
    fontFamily: 'inherit',
    textAlign: 'left'
  };
  const renderLoaded = () => <div style={shellStyle}>
      <button type="button" onClick={handleCopy} aria-label="Copy code" style={copyBtnStyle} onMouseEnter={e => {
    e.currentTarget.style.background = 'rgba(255,255,255,0.25)';
  }} onMouseLeave={e => {
    e.currentTarget.style.background = 'rgba(255,255,255,0.15)';
  }}>
        {copied ? 'Copied!' : 'Copy'}
      </button>
      <pre style={preStyle}>
        <code className={'language-' + language} style={{
    fontSize: '14px'
  }}>
          {content}
        </code>
      </pre>
      {showExpandToggle ? <button type="button" style={toggleLinkStyle} onClick={toggleExpand} aria-expanded={expanded ? 'true' : 'false'} aria-label={expanded ? 'Show less code' : 'See all ' + lineCount + ' lines of code'}>
          {expanded ? '... Show less' : '... See all ' + lineCount + ' lines'}
        </button> : null}
    </div>;
  if (error) {
    return renderErrorBox();
  }
  if (content === null) {
    return renderLoadingBox();
  }
  return renderLoaded();
};

Integrate your email address with Endor Labs and automatically receive policy violations as email notifications.

* [Configure email integration](#configure-email-integration)
  * [Associate an action policy with the email notification](#associate-an-action-policy-with-the-email-notification)
  * [Customize email notification templates](#customize-email-notification-templates)
  * [Data model](#data-model)
* [Run a scan](#run-a-scan)

## Configure email integration

To configure an email integration, follow these steps:

1. Select **User menu** > **Integrations** from the left sidebar.
2. Under **Notifications**, click **Add** on the **Email** card. If you already have an email integration, click **Manage** instead.
3. Click **Add Notification Integration** to open the **Send Notifications to Email** dialog.
4. Enter a **Name** and **Description** for this integration.
5. In **Email addresses**, enter up to eight email addresses separated by commas.
6. Optional: select **Propagate this notification target to all child namespaces** to make this integration available in child namespaces.
7. Click **Add Notification Integration** to save the integration.

### Associate an action policy with the email notification

Users can create action policies to send an email notification when a scan matches policy conditions. For example, if there is a critical or high vulnerability, send an email notification.

To send an email when a scan produces matching findings, create an action policy with a **Send Notification** action that targets your email integration. For the full procedure, see [Create an action policy](/platform-administration/policies/action-policies).

The email-specific choices are:

* Under **Choose an Action**, select **Send Notification**.
* From **Select notification targets**, choose the email integration you created.

From **Select aggregation type**, choose how findings are grouped into notifications.

* **None (Notify for each Finding)** sends a separate notification for each finding.
* **Project** sends a single notification for all findings in a project.
* **Dependency** sends a notification for every dependency.
* **Dependency per Package Version** sends a notification for every unique combination of dependency and package version.

### Customize email notification templates

Endor Labs provides a default template with standard information for the email. You can use the default template or you can choose to edit and customize this template to fit your organization's specific requirements. You can also create custom templates using [Go Templates](https://pkg.go.dev/text/template).

1. Select **User menu** > **Integrations** from the left sidebar.
2. Under **Notifications**, click **Manage** on the **Email** card to view the configured notification integrations.
3. Choose a notification integration, click the ellipsis on the right side, and click **Edit Template**.
4. Make required changes to any of the following templates and click **Save Template**.
   * **Open** - This template applies when Endor Labs raises new notifications.
   * **Update** - This template applies when an existing notification updates, such as when findings change.
   * **Resolve** - This template applies when all findings reported by the notification resolve.
5. Click **Restore to Default** to revert the changes.
6. Use the download icon on the top right corner to download this template.
7. Use the copy icon to copy the information in the template.

### Data model

To create custom templates for email notifications, you must understand the data supplied to the template.

See the `EmailData` message used for **Open** and **Update** templates.

<CodeFile src="/templates/notifications/email_data.json" lang="go" />

See the `ResolvedEmailData` message used for **Resolve** template.

<CodeFile src="/templates/notifications/resolved_email_data.json" lang="go" />

See the following protobuf specification for the `NotificationData` message referenced by `EmailData`.

<CodeFile src="/templates/notifications/notification_data.json" lang="proto" />

To understand Project, Finding, PackageVersion and RepositoryVersion definitions in this protobuf specification, see:

* [Project resource kind](/developers-api/rest-api/using-the-rest-api/data-model/resource-kinds#project)
* [Finding resource kind](/developers-api/rest-api/using-the-rest-api/data-model/resource-kinds#finding)
* [PackageVersion resource kind](/developers-api/rest-api/using-the-rest-api/data-model/resource-kinds#packageversion)
* [RepositoryVersion resource kind](/developers-api/rest-api/using-the-rest-api/data-model/resource-kinds#repositoryversion)

See the following specification to understand a few additional functions available to the template. You can access these functions by using their corresponding keys.

<CodeFile src="/templates/notifications/email_notification_func_map.json" lang="go" />

## Run a scan

Run the endorctl scan on your configured projects. See [endorctl scan commands](/developers-api/cli/commands/scan) for more information.
You can view email notifications of policy violations in your inbox.
