email-construction について
建設プロジェクトチーム向けのメール作成スキルです。RFI への回答、サブミッタル、会議、変更指示、遅延通知などの定型メールを作成できます。
主な機能
- 01RFI 回答メールの作成
- 02サブミッタルと会議メールの作成
- 03変更指示と遅延通知の下書き
- 04SMTP によるメール送信
活用シーン
- 01プロジェクト情報を含む RFI 回答
- 02審査用サブミッタルの送付
- 03会議や変更事項のチームへの通知
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ datadrivenconstruction/ ddc_skills_for_ai_agents_in_construction --skill email-constructionインストール後、Claude Code で/email-constructionを入力して読み込まれたか確認します。
同梱ファイルclaw.jsoninstructions.md
詳細
建設業向けメールの作成
概要
適切な書式、文脈、添付ファイルの取り扱いに対応した、プロフェッショナルな建設業向けメールを作成します。一般的な建設業のコミュニケーションワークフロー向けのテンプレートを用意しています。
建設業でのユースケース
1. RFI 回答メール
プロフェッショナルな RFI 回答メールを作成します。
from dataclasses import dataclass
from datetime import datetime
from typing import Optional, List
@dataclass
class RFIResponse:
rfi_number: str
project_name: str
subject: str
question: str
response: str
responder_name: str
responder_title: str
attachments: List[str] = None
cc_list: List[str] = None
def generate_rfi_response_email(rfi: RFIResponse) -> dict:
"""Generate RFI response email."""
subject = f"RE: RFI #{rfi.rfi_number} - {rfi.subject}"
body = f"""Dear Project Team,
Please find below our response to RFI #{rfi.rfi_number}.
**Project:** {rfi.project_name}
**RFI Number:** {rfi.rfi_number}
**Subject:** {rfi.subject}
**Date:** {datetime.now().strftime('%B %d, %Y')}
---
**QUESTION:**
{rfi.question}
---
**RESPONSE:**
{rfi.response}
---
Please proceed accordingly. If you have any questions regarding this response, please contact us.
{"**Attachments:**" + chr(10) + chr(10).join(f"- {a}" for a in rfi.attachments) if rfi.attachments else ""}
Best regards,
{rfi.responder_name}
{rfi.responder_title}
"""
return {
'subject': subject,
'body': body,
'cc': rfi.cc_list or [],
'attachments': rfi.attachments or []
}
2. サブミッタルトランスミッタルメール
サブミッタルトランスミッタルメールを作成します。
@dataclass
class SubmittalTransmittal:
submittal_number: str
project_name: str
spec_section: str
description: str
items: List[dict]
action_required: str
due_date: str
sender_name: str
sender_company: str
def generate_submittal_email(submittal: SubmittalTransmittal) -> dict:
"""Generate submittal transmittal email."""
subject = f"Submittal {submittal.submittal_number} - {submittal.spec_section} - {submittal.description}"
items_list = "\n".join(
f" {i+1}. {item['description']} ({item.get('copies', 1)} copies)"
for i, item in enumerate(submittal.items)
)
body = f"""Dear Design Team,
Please find attached Submittal {submittal.submittal_number} for your review.
**Project:** {submittal.project_name}
**Submittal No:** {submittal.submittal_number}
**Spec Section:** {submittal.spec_section}
**Description:** {submittal.description}
**Items Transmitted:**
{items_list}
**Action Required:** {submittal.action_required}
**Response Requested By:** {submittal.due_date}
Please review and return with your comments at your earliest convenience.
If you have any questions, please don't hesitate to contact us.
Best regards,
{submittal.sender_name}
{submittal.sender_company}
"""
return {
'subject': subject,
'body': body,
'priority': 'normal'
}
3. 会議通知メール
会議の招待メールを作成します。
@dataclass
class MeetingNotice:
meeting_type: str # 'OAC', 'Subcontractor', 'Safety', 'Coordination'
project_name: str
date: str
time: str
location: str
virtual_link: Optional[str]
agenda_items: List[str]
attendees: List[str]
organizer_name: str
def generate_meeting_notice(meeting: MeetingNotice) -> dict:
"""Generate meeting notice email."""
subject = f"{meeting.meeting_type} Meeting - {meeting.project_name} - {meeting.date}"
agenda = "\n".join(f" {i+1}. {item}" for i, item in enumerate(meeting.agenda_items))
location_info = meeting.location
if meeting.virtual_link:
location_info += f"\n Virtual Option: {meeting.virtual_link}"
body = f"""Dear Team,
You are invited to the {meeting.meeting_type} Meeting for {meeting.project_name}.
**Meeting Details:**
- **Date:** {meeting.date}
- **Time:** {meeting.time}
- **Location:** {location_info}
**Agenda:**
{agenda}
**Attendees:**
{', '.join(meeting.attendees)}
Please confirm your attendance by replying to this email.
If you cannot attend, please send a delegate and notify the organizer.
Regards,
{meeting.organizer_name}
Project Manager
"""
return {
'subject': subject,
'body': body,
'to': meeting.attendees,
'calendar_invite': {
'start': f"{meeting.date} {meeting.time}",
'duration': 60,
'location': meeting.location
}
}
4. 変更指示通知
変更指示の通知メールを作成します。
@dataclass
class ChangeOrderNotification:
co_number: str
project_name: str
description: str
amount: float
schedule_impact: str
reason: str
status: str # 'Pending', 'Approved', 'Rejected'
sender_name: str
sender_title: str
def generate_change_order_email(co: ChangeOrderNotification) -> dict:
"""Generate change order notification email."""
subject = f"Change Order #{co.co_number} - {co.status} - {co.project_name}"
amount_str = f"${co.amount:,.2f}"
if co.amount < 0:
amount_str = f"(${abs(co.amount):,.2f}) Credit"
body = f"""Dear Project Team,
This email is to notify you of Change Order #{co.co_number} for {co.project_name}.
**Change Order Details:**
- **CO Number:** {co.co_number}
- **Status:** {co.status}
- **Description:** {co.description}
**Financial Impact:**
- **Amount:** {amount_str}
**Schedule Impact:**
- {co.schedule_impact}
**Reason for Change:**
{co.reason}
{"Please review the attached documentation and provide your approval." if co.status == 'Pending' else ""}
{"This change order has been approved. Please proceed accordingly." if co.status == 'Approved' else ""}
If you have any questions, please contact the project team.
Best regards,
{co.sender_name}
{co.sender_title}
"""
return {
'subject': subject,
'body': body,
'priority': 'high' if co.status == 'Pending' else 'normal',
'flag': co.status == 'Pending'
}
5. 日報メール
日報の配信メールを作成します。
@dataclass
class DailyReportEmail:
project_name: str
report_date: str
report_number: int
weather: str
workforce_total: int
work_summary: List[str]
issues: List[str]
sender_name: str
def generate_daily_report_email(report: DailyReportEmail) -> dict:
"""Generate daily report distribution email."""
subject = f"Daily Report #{report.report_number} - {report.project_name} - {report.report_date}"
work_items = "\n".join(f"• {item}" for item in report.work_summary)
issues_text = "\n".join(f"• {issue}" for issue in report.issues) if report.issues else "None"
body = f"""Daily Construction Report
**Project:** {report.project_name}
**Date:** {report.report_date}
**Report #:** {report.report_number}
---
**Weather:** {report.weather}
**Total Workforce:** {report.workforce_total} workers on-site
---
**Work Completed:**
{work_items}
---
**Issues/Delays:**
{issues_text}
---
Full report attached. Please contact the site office with any questions.
{report.sender_name}
Site Superintendent
"""
return {
'subject': subject,
'body': body,
'attachments': [f'Daily_Report_{report.report_number}.pdf']
}
6. 遅延通知メール
正式な遅延通知を作成します。
@dataclass
class DelayNotice:
project_name: str
contract_number: str
delay_type: str # 'Excusable', 'Non-Excusable', 'Compensable'
cause: str
affected_activities: List[str]
original_completion: str
revised_completion: str
days_impacted: int
mitigation_plan: str
sender_name: str
sender_title: str
def generate_delay_notice_email(delay: DelayNotice) -> dict:
"""Generate formal delay notice email."""
subject = f"NOTICE OF DELAY - {delay.project_name} - {delay.days_impacted} Days"
activities = "\n".join(f" - {a}" for a in delay.affected_activities)
body = f"""NOTICE OF DELAY
**Project:** {delay.project_name}
**Contract No:** {delay.contract_number}
**Date:** {datetime.now().strftime('%B %d, %Y')}
---
Dear Owner/Owner's Representative,
In accordance with the contract requirements, this letter serves as formal notice of a delay to the project schedule.
**Delay Classification:** {delay.delay_type}
**Cause of Delay:**
{delay.cause}
**Affected Activities:**
{activities}
**Schedule Impact:**
- Original Completion Date: {delay.original_completion}
- Revised Completion Date: {delay.revised_completion}
- Calendar Days Impacted: {delay.days_impacted}
**Mitigation Plan:**
{delay.mitigation_plan}
We request a meeting to discuss this matter and coordinate recovery efforts. Please contact us at your earliest convenience.
This notice is provided without prejudice to any rights or remedies available under the contract.
Respectfully,
{delay.sender_name}
{delay.sender_title}
"""
return {
'subject': subject,
'body': body,
'priority': 'high',
'read_receipt': True,
'delivery_receipt': True
}
メール送信の連携
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
class ConstructionEmailSender:
"""Send construction emails via SMTP."""
def __init__(self, smtp_server: str, smtp_port: int, username: str, password: str):
self.smtp_server = smtp_server
self.smtp_port = smtp_port
self.username = username
self.password = password
def send(self, to: List[str], email_data: dict, from_addr: str = None):
"""Send email with optional attachments."""
msg = MIMEMultipart()
msg['From'] = from_addr or self.username
msg['To'] = ', '.join(to)
msg['Subject'] = email_data['subject']
if email_data.get('cc'):
msg['Cc'] = ', '.join(email_data['cc'])
if email_data.get('priority') == 'high':
msg['X-Priority'] = '1'
msg.attach(MIMEText(email_data['body'], 'plain'))
# Add attachments
for attachment_path in email_data.get('attachments', []):
with open(attachment_path, 'rb') as f:
part = MIMEApplication(f.read())
part.add_header('Content-Disposition', 'attachment',
filename=attachment_path.split('/')[-1])
msg.attach(part)
# Send
with smtplib.SMTP(self.smtp_server, self.smtp_port) as server:
server.starttls()
server.login(self.username, self.password)
recipients = to + email_data.get('cc', [])
server.sendmail(msg['From'], recipients, msg.as_string())
DDC パイプラインとの連携
# Example: Auto-generate RFI response email from RFI log
import pandas as pd
# Load RFI log
rfi_log = pd.read_excel("RFI_Log.xlsx")
# Get pending RFI
pending_rfi = rfi_log[rfi_log['status'] == 'Response Ready'].iloc[0]
# Generate email
rfi = RFIResponse(
rfi_number=pending_rfi['rfi_number'],
project_name=pending_rfi['project'],
subject=pending_rfi['subject'],
question=pending_rfi['question'],
response=pending_rfi['response'],
responder_name='John Smith',
responder_title='Project Architect',
attachments=['SK-001.pdf']
)
email_data = generate_rfi_response_email(rfi)
print(f"Subject: {email_data['subject']}")
print(email_data['body'])
メールテンプレートライブラリ
建設業でよく使用されるメールテンプレート:
| テンプレート | ユースケース |
|---|---|
| RFI 回答 | 情報提供依頼への回答 |
| サブミッタルトランスミッタル | レビュー用のサブミッタルの送付 |
| 会議通知 | OAC、協力会社、安全に関する会議 |
| 変更指示 | CO の通知と承認 |
| 日報 | 日報の配信 |
| 遅延通知 | 正式な遅延通知 |
| 支払申請 | 支払申請の提出 |
| パンチリスト | パンチリスト項目の通知 |
| クローズアウト | 保証書およびクローズアウト書類 |
リソース
- プロフェッショナルなメールの書き方:メールは簡潔で、具体的なアクションにつながる内容にします
- 建設業のメール作成におけるベストプラクティス:プロジェクト名と参照番号を必ず記載します
- 法的な考慮事項:遅延通知には契約上の要件が定められている場合があります
コメント
Markdown 対応