@@ -160,7 +160,9 @@ def __init__(self, source_message: Optional[BotMessage] = None):
160160 'password' : config .email_password ,
161161 'receivers' : config .email_receivers or ([config .email_sender ] if config .email_sender else []),
162162 }
163-
163+ # Stock-to-email group routing (Issue #268)
164+ self ._stock_email_groups = getattr (config , 'stock_email_groups' , None ) or []
165+
164166 # Pushover 配置
165167 self ._pushover_config = {
166168 'user_key' : getattr (config , 'pushover_user_key' , None ),
@@ -274,6 +276,43 @@ def _is_astrbot_configured(self) -> bool:
274276 def _is_email_configured (self ) -> bool :
275277 """检查邮件配置是否完整(只需邮箱和授权码)"""
276278 return bool (self ._email_config ['sender' ] and self ._email_config ['password' ])
279+
280+ def get_receivers_for_stocks (self , stock_codes : List [str ]) -> List [str ]:
281+ """
282+ Look up email receivers for given stock codes based on stock_email_groups.
283+ Returns union of receivers for all matching groups; falls back to default if none match.
284+ """
285+ if not stock_codes or not self ._stock_email_groups :
286+ return self ._email_config ['receivers' ]
287+ seen : set = set ()
288+ result : List [str ] = []
289+ for stocks , emails in self ._stock_email_groups :
290+ for code in stock_codes :
291+ if code in stocks :
292+ for e in emails :
293+ if e not in seen :
294+ seen .add (e )
295+ result .append (e )
296+ break
297+ return result if result else self ._email_config ['receivers' ]
298+
299+ def get_all_email_receivers (self ) -> List [str ]:
300+ """
301+ Return union of all configured email receivers (all groups + default).
302+ Used for market review which should go to everyone.
303+ """
304+ seen : set = set ()
305+ result : List [str ] = []
306+ for _ , emails in self ._stock_email_groups :
307+ for e in emails :
308+ if e not in seen :
309+ seen .add (e )
310+ result .append (e )
311+ for e in self ._email_config ['receivers' ]:
312+ if e not in seen :
313+ seen .add (e )
314+ result .append (e )
315+ return result
277316
278317 def _is_pushover_configured (self ) -> bool :
279318 """检查 Pushover 配置是否完整"""
@@ -1782,13 +1821,16 @@ def _post_payload(payload: Dict[str, Any]) -> bool:
17821821
17831822 return _post_payload (text_payload )
17841823
1785- def send_to_email (self , content : str , subject : Optional [str ] = None ) -> bool :
1824+ def send_to_email (
1825+ self , content : str , subject : Optional [str ] = None , receivers : Optional [List [str ]] = None
1826+ ) -> bool :
17861827 """
17871828 通过 SMTP 发送邮件(自动识别 SMTP 服务器)
17881829
17891830 Args:
17901831 content: 邮件内容(支持 Markdown,会转换为 HTML)
17911832 subject: 邮件主题(可选,默认自动生成)
1833+ receivers: 收件人列表(可选,默认使用配置的 receivers)
17921834
17931835 Returns:
17941836 是否发送成功
@@ -1799,7 +1841,7 @@ def send_to_email(self, content: str, subject: Optional[str] = None) -> bool:
17991841
18001842 sender = self ._email_config ['sender' ]
18011843 password = self ._email_config ['password' ]
1802- receivers = self ._email_config ['receivers' ]
1844+ receivers = receivers or self ._email_config ['receivers' ]
18031845
18041846 try :
18051847 # 生成主题
@@ -3063,14 +3105,21 @@ def _send_astrbot(self, content: str) -> bool:
30633105 logger .error (f"AstrBot 发送异常: { e } " )
30643106 return False
30653107
3066- def send (self , content : str ) -> bool :
3108+ def send (
3109+ self ,
3110+ content : str ,
3111+ email_stock_codes : Optional [List [str ]] = None ,
3112+ email_send_to_all : bool = False
3113+ ) -> bool :
30673114 """
30683115 统一发送接口 - 向所有已配置的渠道发送
30693116
30703117 遍历所有已配置的渠道,逐一发送消息
30713118
30723119 Args:
30733120 content: 消息内容(Markdown 格式)
3121+ email_stock_codes: 股票代码列表(可选,用于邮件渠道路由到对应分组邮箱,Issue #268)
3122+ email_send_to_all: 邮件是否发往所有配置邮箱(用于大盘复盘等无股票归属的内容)
30743123
30753124 Returns:
30763125 是否至少有一个渠道发送成功
@@ -3100,7 +3149,12 @@ def send(self, content: str) -> bool:
31003149 elif channel == NotificationChannel .TELEGRAM :
31013150 result = self .send_to_telegram (content )
31023151 elif channel == NotificationChannel .EMAIL :
3103- result = self .send_to_email (content )
3152+ receivers = None
3153+ if email_send_to_all and self ._stock_email_groups :
3154+ receivers = self .get_all_email_receivers ()
3155+ elif email_stock_codes and self ._stock_email_groups :
3156+ receivers = self .get_receivers_for_stocks (email_stock_codes )
3157+ result = self .send_to_email (content , receivers = receivers )
31043158 elif channel == NotificationChannel .PUSHOVER :
31053159 result = self .send_to_pushover (content )
31063160 elif channel == NotificationChannel .PUSHPLUS :
0 commit comments